2020년 3월 5일 목요일

[CSharp] ezWpfPython


1. EzWpfPython


import clr
clr.AddReference("PresentationFramework")
clr.AddReference("PresentationCore");
clr.AddReference('WindowsBase')
clr.AddReference('System.Data')
clr.AddReference('System.ComponentModel')
clr.AddReference('System.Windows.Forms')

import System
from System import *
from System.Data import *
from System.Type import GetType
from System.Threading.Tasks import Task
from System.ComponentModel import SortDescription
from System.ComponentModel import ListSortDirection
from System.Windows import *
from System.Windows.Controls import *
from System.Windows.Controls.Primitives import *
from System.Windows.Media import *
from System.Windows.Media.Imaging import *
from System.Windows.Media.Effects import *
from System.Windows.Shapes import Rectangle
from System.Windows.Data import Binding
from System.Windows.Data import CollectionViewSource
from System.Windows.Ink import Stroke
from System.Windows.Forms import ( FolderBrowserDialog, DialogResult )
from Microsoft.Win32 import ( OpenFileDialog, SaveFileDialog )

'''
System:: 
    Data, Uri, UriKind, Timers, Threading, IO
System.Windows::
    Application, Window, Clipboard, DataFormats, Visibility, Thickness,
    TextWrapping, HorizontalAlignment, VerticalAlignment, MessageBox,
    MessageBoxButton, MessageBoxResult, GridUnitType, GridLength,
    TextAlignment
System.Windows.Controls::   
    GroupBox, Border, StackPanel, Orientation,
    Grid. RowDefinition. ColumnDefinition, TabControl, TabItem,
    ContextMenu, Menu, MenuItem, ToolTip, Separator, Image
    Label, TextBlock, Button, CheckBox, TextBox, ComboBox, ListBox
    ListView, ListViewItem, TreeView, TreeViewItem, GridView
    GridViewColumn, ProgressBar, DatePicker, Slider, ScrollViewer
    WebBrowser, ToolBarTray, ToolBar, ScrollBarVisibility, Canvas
System.Windows.Controls.Primitives
    ToggleButton, TickPlacement, StatusBar, StatusBarItem
System.Windows.Media    
    Brushes, Stretch, VisualTreeHelper
System.Windows.Media.Imaging
    BitmapImage, BitmapFrame
System.Data
    DataTable DataView DataColumn
System.Windows.Forms
    FolderBrowserDialog DialogResult
'''

#
# Control Table
#

_window__ctrl_table = {}

def GetControl(name):
    return _window__ctrl_table.get(name)

def GetWpfControl(name):
    if _window__ctrl_table.get(name): return _window__ctrl_table[name].ctrl;

def DumpControlTable():
    for k,v in _window__ctrl_table.items():
        print(k,v)
        

#
# Controls
#

class Class:
    def __init__(self,**kwargs): self.__dict__.update(kwargs)
    
def GetHandler(handler):
    return lambda sender,args: handler(Class(sender=sender,args=args))
    '''
    def Handler(sender,args):
        handler(Class(sender=sender,args=args))
    return Handler
    '''
class WpfControl():
    def Initialize(self,h):
        if h.get('key'): _window__ctrl_table[h['key']] = self
        if h.get('tooltip'): self.SetToolTip(h['tooltip'])
        if h.get('menu'): self.SetContextMenu(h['menu'])
        if h.get('width'): self.ctrl.Width = h['width']
        if h.get('height'): self.ctrl.Height = h['height']
        if h.get('drop'): self.SetFileDropHandler(h['drop'])
        self.ctrl.Margin  = Thickness(5)
        self.ctrl.Padding = Thickness(1)
    def SetMargin(self,l,t,r,b):
        self.ctrl.Margin = System.Windows.Thickness(l,t,r,b)
    def ShadowEffect(self):
        from System.Windows.Media.Effects import DropShadowBitmapEffect
        self.ctrl.BitmapEffect = DropShadowBitmapEffect()
    def SetFontSize(self,size):
        self.ctrl.FontSize = size
    def SetToolTip(self,tooltip):
        tip = ToolTip()
        tip.Content = tooltip
        self.ctrl.ToolTip = tip
    def SetContextMenu(self,menu_table):
        menu = ContextMenu()
        for m in menu_table:
            menu.Items.Add(WpfMenu(m['name'],m['item']).ctrl)         
        self.ctrl.ContextMenu = menu
    def SetFileDropHandler(self,handler):
        SetFileDropHandler(self.ctrl,handler)

class WpfSpacer(WpfControl):
    def __init__(self,h):
        self.ctrl = Label()
        if not h.get('width'): h['expand'] = True
        self.Initialize(h)
    def SetValue(self,text):
        self.ctrl.Content = text

class WpfLabel(WpfControl):
    def __init__(self,h):
        self.ctrl = Label()
        self.Initialize(h)
        if h.get('label'): self.SetValue(h['label'])
        if h.get('fontsize'): self.SetFontSize(h['fontsize'])
    def SetValue(self,text):
        self.ctrl.Content = text

class WpfImageView(WpfControl):
    def __init__(self,h):
        self.ctrl = Label()
        self.Initialize(h)
        self.image = Image()
        self.image.HorizontalAlignment = HorizontalAlignment.Center
        self.image.VerticalAlignment = VerticalAlignment.Center
        if h.get('image'): self.image.Source = BitmapImage(System.Uri(h['image'],System.UriKind.Relative))
        if h.get('stretch'): self.Stretch(h['stretch'])
        else: self.StretchUniform()
        if h.get('size'): self.image.Height = float(h['size']); self.image.Width = float(h['size'])
        if h.get('scroll') and h['scroll']:
            scroll = ScrollViewer()
            scroll.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
            scroll.Content = self.image;
            self.ctrl.Content = scroll
        elif h.get('multiple') and h['multiple']:
            stack = StackPanel()
            stack.Orientation = Orientation.Horizontal
            stack.Children.Add(self.image)
            self.ctrl.Content = stack 
        else:
            self.ctrl.Content = self.image       
    def StretchNone(self): self.image.Stretch = Stretch.None
    def StretchFill(self): self.image.Stretch = Stretch.Fill
    def StretchUniform(self): self.image.Stretch = Stretch.Uniform
    def StretchUniformToFill(self): self.image.Stretch = Stretch.UniformToFill
    def Stretch(self,stretch):
        if stretch == 'none': self.StretchNone()
        elif stretch == 'fill': self.StretchFill()
        elif stretch == 'uniform': self.StretchUniform()
        elif stretch == 'uniformfill': self.StretchUniformToFill()

class WpfButton(WpfControl):
    def __init__(self,h):
        self.ctrl = Button()
        self.Initialize(h)
        if h.get('fontsize'): self.SetFontSize(h['fontsize'])
        if h.get('handler'): self.ctrl.Click += GetHandler(h['handler'])
        stack = StackPanel()
        if h.get('orientation') and h['orientation'] == 'vertical': 
            stack.Orientation = Orientation.Vertical
        else:
            stack.Orientation = Orientation.Horizontal
        self.ctrl.Content = stack
        if h.get('image'):
            image = Image()
            image.Source = BitmapImage(System.Uri(h['image'],System.UriKind.Relative))
            image.VerticalAlignment = VerticalAlignment.Center
            image.Stretch = Stretch.Fill #Stretch.None
            if h.get('size'): image.Height = float(h['size']);  image.Width = float(h['size'])
            stack.Children.Add(image)
        if h.get('label'): 
            text = TextBlock()
            text.Text = h['label']
            text.TextAlignment = TextAlignment.Center
            stack.Children.Add(text);            

class WpfToggleButton(WpfControl):
    def __init__(self,h):
        self.ctrl = ToggleButton()
        self.Initialize(h)
        if h.get('label'): self.ctrl.Content = h.get('label')
        if h.get('handler'): self.ctrl.Click += GetHandler(h['handler'] )
    def IsSelected(self):
        return self.ctrl.IsChecked
     
class WpfCheckBox(WpfControl):
    def __init__(self,h):
        self.ctrl = CheckBox()
        self.ctrl.VerticalAlignment = VerticalAlignment.Center
        self.ctrl.VerticalContentAlignment = VerticalAlignment.Center
        self.Initialize(h)
        if h.get('label'): self.ctrl.Content = h['label']
        if h.get('fontsize'): self.SetFontSize(h['fontsize'])
        if h.get('handler'): self.ctrl.Click += GetHandler(h['handler'] )
    def GetValue(self): return self.ctrl.IsChecked

class WpfTextBox(WpfControl):
    def __init__(self,h):
        self.text = TextBox()
        self.ctrl = self.text
        self.Initialize(h)
        if h.get('width'): self.SetWidth(h['width'])
        if h.get('fontsize'): self.SetFontSize(h['fontsize'])
        if h.get('multiline'): 
            self.ctrl.AcceptsReturn = True
            self.ctrl.AcceptsTab = True
            self.ctrl.TextWrapping = TextWrapping.NoWrap
            self.ctrl.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto
            self.ctrl.VerticalScrollBarVisibility   = ScrollBarVisibility.Auto
        if h.get('toolbar') and h['toolbar']:
            self.vbox = WpfVBox()
            self.hbox = WpfHBox()
            self.hbox.AddItem(self.Button("Clear", self.ClearHandler))
            self.hbox.AddItem(self.Button("Copy", self.CopyHandler))
            self.hbox.AddItem(self.Button("CopyAll", self.CopyAllHandler))
            self.hbox.AddItem(self.Button("Paste", self.PasteHandler))
            self.hbox.AddItem(self.Button("PasteHtml", self.PasteHtmlHandler))
            self.vbox.AddItem(self.hbox.ctrl)
            self.vbox.AddItem(self.text,{'expand':True})
            self.ctrl = self.vbox.ctrl
    def Button(self,label,handler):
        button = Button()
        button.Content = label
        button.Click += handler
        return button
    def ClearHandler(self,sender,args):
        self.text.Clear()
    def CopyHandler(self,sender,args):
        self.text.Copy()
    def CopyAllHandler(self,sender,args):
        self.text.SelectAll()
        self.text.Copy()
    def PasteHandler(self,sender,args):
        self.text.Paste()
    def PasteHtmlHandler(self,sender,args):
        self.text.Text = ClipboardGetHtmlData()
    def Clear(self):
        self.text.Text = ""
    def GetValue(self):
        return self.text.Text
    def SetValue(self,text):
        self.text.Text = text
    def AppendText(self,text):
        self.text.Text += text
    def SetWidth(self,width):
        self.text.Width = width
    def ScrollToEnd(self):
        self.text.ScrollToEnd()
    def SetWrap(self,wrap):
        self.text.TextWrapping = TextWrapping.Wrap if wrap else TextWrapping.NoWrap
        
class WpfChoiceBox(WpfControl):
    def __init__(self,h):
        self.ctrl = ComboBox()
        self.Initialize(h)
        self.init_ComboBox(h)
    def init_ComboBox(self,h):
        if h.get('fontsize'): self.SetFontSize(h['fontsize'])
        if h.get('handler'): self.ctrl.SelectionChanged += GetHandler(h['handler'] )
        if h.get('items'):
            self.ctrl.ItemsSource = h['items']
            self.ctrl.SelectedIndex = 0     
    def GetValue(self): return ctrl.Text
    def GetAddedItem(self,args): return args.AddedItems[0]

class WpfComboBox(WpfChoiceBox):
    def __init__(self,h):
        self.ctrl = ComboBox()
        self.Initialize(h)
        self.init_ComboBox(h)
        self.ctrl.IsEditable=True
        self.ctrl.IsReadOnly=False

class WpfListBox(WpfControl):
    def __init__(self,h):
        self.ctrl = ListBox()
        self.Initialize(h)
        if h.get('fontsize'): self.SetFontSize(h['fontsize'])
        if h.get('handler'): self.ctrl.SelectionChanged += GetHandler(h['handler'] )
        if h.get('items'):
            self.ctrl.ItemsSource = h['items']
            self.ctrl.SelectedIndex = 0
    def GetValue(self): return self.ctrl.SelectedItem

class WpfTableView(WpfControl):
    def __init__(self,h):
        self.ctrl = ListView()
        self.table = DataTable('table')
        self.Initialize(h)
        if h.get('fontsize'): self.SetFontSize(h['fontsize'])
        #if h.get('handler'): self.ctrl.SelectionChanged += h['handler']
        if h.get('handler'): self.ctrl.SelectionChanged += GetHandler(h['handler'])
        self.grid = GridView()
        self.grid.AllowsColumnReorder = True; 
        self.grid.ColumnHeaderToolTip = "ListView Column Info";   
        if h.get('columns'): 
            items = h['columns']
            widths = None
            labels = None
            if h.get('widths'): widths = h['widths']
            if h.get('labels'): labels = h['labels']
            for i in range(0,len(items)):
                width = widths[i] if widths else None
                label = labels[i] if labels else None
                self.AddColumn(items[i],width,label)     
        self.ctrl.View = self.grid
        self.ctrl.ItemsSource = self.table.DefaultView
        self.ctrl.AddHandler(GridViewColumnHeader.ClickEvent, RoutedEventHandler(self.OnColumnHeaderClick))
        self.sort_dir = ListSortDirection.Ascending
    def AddColumn(self,name,width=None,label=None):
        col = GridViewColumn()
        if width: col.Width = width
        col.Header = label if label else name
        col.DisplayMemberBinding = Binding(name)
        self.grid.Columns.Add(col); 
        item = DataColumn(name, GetType("System.String"))
        self.table.Columns.Add(item)
        '''
        item = DataColumn()
        item.DataType = System.Type.GetType("System.String");
        item.ColumnName = name
        item.AutoIncrement = False
        item.Header = label #if label else name
        item.ReadOnly = False
        item.Unique = False       
        self.table.Columns.Add(item)
        '''
    def AddItem(self,items):
        item = self.table.NewRow()
        for key, value in items.items():
            item[key] = value;
        self.table.Rows.Add(item);
    def GetValue(self): return self.ctrl.SelectedItem
    def GetSelectedItems(self): return self.ctrl.SelectedItems
    def AddSortColumnName(self,col_name,ascending=True):
        view = CollectionViewSource.GetDefaultView(self.ctrl.ItemsSource)
        if ascending:
            view.SortDescriptions.Add(SortDescription(col_name, ListSortDirection.Ascending))
        else:
            view.SortDescriptions.Add(SortDescription(col_name, ListSortDirection.Descending))
    def ColumnSort(self,col_name,direction):
        view = CollectionViewSource.GetDefaultView(self.ctrl.ItemsSource)
        view.SortDescriptions.Clear()
        view.SortDescriptions.Add(SortDescription(col_name, direction))
        view.Refresh()
    def OnColumnHeaderClick(self,sedner,event):
        headerClicked = event.OriginalSource
        columnBinding = headerClicked.Column.DisplayMemberBinding
        if self.sort_dir == ListSortDirection.Descending:
            self.sort_dir = ListSortDirection.Ascending 
            headerClicked.Column.Header = columnBinding.Path.Path + " (+)"
        else: 
            self.sort_dir = ListSortDirection.Descending
            headerClicked.Column.Header = columnBinding.Path.Path + " (-)"
        self.ColumnSort( columnBinding.Path.Path, self.sort_dir ) #headerClicked.Column.Header

        
class WpfTreeView(WpfControl):
    def __init__(self,h):
        self.root = TreeViewItem()
        self.root.Header = h['name']
        self.root.IsExpanded = True
        self.ctrl = TreeView()
        self.ctrl.Items.Add(self.root)
        self.Initialize(h)
        if h.get('handler'): self.ctrl.SelectedItemChanged  += GetHandler(h['handler'] )
    def AddRootItem(self,label):
        return self.AddItem(label)
    def AddItem(self,label,parent=None):
        item = TreeViewItem()
        item.Header = label
        item.IsExpanded = True
        if parent: parent.Items.Add(item)
        else: self.root.Items.Add(item)
        return item
    def GetSelectedIndex(self):
        pass
    def GetSelectedItem(self):
        return self.ctrl.SelectedItem
    def GetSelectedItemText(self):
        return self.ctrl.SelectedItem.Header.ToString()
    def GetSelectedItemPath(self,delim=""):
        item = self.ctrl.SelectedItem
        return self.GetItemPath(item,delim)
    def GetItemPath(self,item,delim=""):
        path = item.Header.ToString()
        while type(item.Parent) == TreeViewItem:
            item = item.Parent
            path = item.Header.ToString() + delim + path
        return path
    def GetParentItem(self,item):
        return item.Parent
    def GetItemValue(self,item):
        return item.ToString()

class WpfWebView(WpfControl):
    def __init__(self,h):
        self.web = WebBrowser()
        self.ctrl = self.web
        self.web.Navigated += self.LoadedHandler
        if h.get('fontsize'): self.SetFontSize(h['fontsize'])
        if h.get('toolbar') and h['toolbar']:
            self.vbox = WpfVBox()
            self.hbox = WpfHBox()
            self.text = TextBox()
            self.hbox.AddItem(self.Button("<-", self.BackHandler))
            self.hbox.AddItem(self.Button("->", self.ForwardHandler))
            self.hbox.AddItem(self.Button("<>", self.RefreshHandler))
            self.hbox.AddItem(self.text, {'expand':True})
            self.hbox.AddItem(self.Button("Go", self.GoHandler))
            self.vbox.AddItem(self.hbox.ctrl)
            self.vbox.AddItem(self.web,{'expand':True})
            self.ctrl = self.vbox.ctrl
        if h.get('uri'): self.Go(h['uri'])
    def Button(self,label,handler):
        button = Button()
        button.Content = label
        button.Click += handler
        return button
    def LoadedHandler(self,sender,args):
        self.text.Text = self.web.Source.ToString()
    def GoHandler(self,sender,args):
        uri = self.text.Text
        if not uri.startswith('http'):
            uri = "http://" + uri
            self.text.Text = uri
        self.Go(uri)
    def BackHandler(self,sender,args): self.Back()
    def ForwardHandler(self,sender,args): self.Forward()
    def RefreshHandler(self,sender,args): self.Refresh()
    def Go(self,uri): self.web.Navigate(System.Uri(uri, System.UriKind.RelativeOrAbsolute));
    def Back(self):
        if self.web.CanGoBack: self.web.GoBack()
    def Forward(self):
        if self.web.CanGoForward: self.web.GoForward()
    def Refresh(self):
        self.web.Refresh()
    def Html(self): return self.web.Document.documentElement.InnerHtml
           
class WpfProgressBar(WpfControl):
    def __init__(self,h):   
        self.ctrl = ProgressBar()
        #self.ctrl.IsIndeterminate = True
        #self.ctrl.Margin = new Thickness(10,0,10,10);
        self.ctrl.Visibility = Visibility.Visible;
        self.ctrl.Width = 100;
        self.ctrl.Height = 16;
        #self.ctrl.Foreground = System.Windows.Media.Brushes.Green;
        #self.ctrl.Background = System.Windows.Media.Brushes.Red;
        #self.ctrl.Style = ProgressBarStyle.Continuous #Marquee
        self.ctrl.Maximum = 100
        self.ctrl.Value = 0
        #self.ctrl.FlowDirection = FlowDirection.LeftToRight
        self.Initialize(h)
    def GetValue(self):
        return self.ctrl.Value
    def SetValue(self,v):
        self.ctrl.Value = v


class WpfDatePicker(WpfControl):
    def __init__(self,h):   
        self.ctrl = DatePicker()
        self.Initialize(h)
        if h.get('handler'): self.ctrl.SelectedDateChanged += GetHandler(h['handler'] )
    def GetValue(self):
        return self.ctrl.Text
    def SetValue(self,v):
        self.ctrl.Text = v

class WpfSlider(WpfControl):
    def __init__(self,h):   
        self.ctrl = Slider()
        self.Initialize(h)
        if h.get('handler'): self.ctrl.ValueChanged += GetHandler(h['handler'] )
        self.ctrl.Width = 100;
        self.ctrl.Height = 16;        
        self.ctrl.Minimum = h['min'] if h.get('min') else 0
        self.ctrl.Maximum = h['max'] if h.get('max') else 100     
        self.ctrl.Value = h['value'] if h.get('value') else 0
        self.ctrl.SmallChange = 1
        self.ctrl.LargeChange = 10
        self.ctrl.TickPlacement = TickPlacement.BottomRight
        self.ctrl.TickFrequency = 10
    def GetValue(self):
        return self.ctrl.Value
    def SetValue(self,v):
        self.ctrl.Value = v
              
#
# Containers
#

class WpfBorderGrid():
    def __init__(self):
        self.grid = Grid()
        self.ctrl = Border()
        self.ctrl.HorizontalAlignment = HorizontalAlignment.Left
        self.ctrl.VerticalAlignment = VerticalAlignment.Top
        #border.BorderBrush = BorderBrush.Black
        self.ctrl.BorderThickness = 2
        self.ctrl.Content = self.grid
    def AddRow(self,height=1,expand=False,span=1):
        if expand: length = GridLength(height, GridUnitType.Star)
        else:      length = GridLength(height, GridUnitType.Auto)
        self.grid.RowDefinitions.Add(RowDefinition(Height = length))
    def AddColumn(self,width=1,expand=False,span=1):
        if expand: length = GridLength(width, GridUnitType.Star)
        else:      length = GridLength(width, GridUnitType.Auto)
        self.grid.ColumnDefinitions.Add(ColumnDefinition(Width = length))
    def AddItem(self,item,row,col,rowspan=1,colspan=1):
        Grid.SetRow(item, row);
        Grid.SetColumn(item, col);
        self.grid.Children.Add(item)
        if rowspan > 1: item.SetValue(Grid.RowSpanProperty, rowspan);
        if colspan > 1: item.SetValue(Grid.ColumnSpanProperty, colspan);
        
class WpfGrid():
    def __init__(self):
        self.ctrl = Grid()
    def AddRow(self,height=1,expand=False,span=1):
        if expand: length = GridLength(height, GridUnitType.Star)
        else:      length = GridLength(height, GridUnitType.Auto)
        self.ctrl.RowDefinitions.Add(RowDefinition(Height = length))
    def AddColumn(self,width=1,expand=False,span=1):
        if expand: length = GridLength(width, GridUnitType.Star)
        else:      length = GridLength(width, GridUnitType.Auto)
        self.ctrl.ColumnDefinitions.Add(ColumnDefinition(Width = length))
    def AddItem(self,item,row,col,rowspan=1,colspan=1):
        Grid.SetRow(item, row);
        Grid.SetColumn(item, col);
        self.ctrl.Children.Add(item)
        if rowspan > 1: item.SetValue(Grid.RowSpanProperty, rowspan);
        if colspan > 1: item.SetValue(Grid.ColumnSpanProperty, colspan);
        
class WpfVBox():
    def __init__(self):
        self.ctrl = Grid()
        self.ctrl.Margin = Thickness(1)
        self.rows = 0
    def AddItem(self,item,attr=None,height=1):
        if attr and attr.get('expand'): length = GridLength(height, GridUnitType.Star)
        else: length = GridLength(height, GridUnitType.Auto)
        self.ctrl.RowDefinitions.Add(RowDefinition(Height = length))
        Grid.SetRow(item, self.rows);
        if attr and attr.get('group'):
            group = GroupBox()
            group.Header = attr['group']
            group.AddChild(item)
            Grid.SetRow(group, self.rows);
            self.ctrl.Children.Add(group)
        else:
            if attr and attr.get('border') and attr['border']:
                rect = Rectangle()
                rect.Stroke = Brushes.Gray
                rect.Fill = Brushes.Transparent
                Grid.SetRow(rect, self.rows);
                self.ctrl.Children.Add(rect)
            self.ctrl.Children.Add(item)
        self.rows = self.rows + 1
    def AddSplitter(self,width=1):
        from System.Windows.Controls import GridSplitter
        item = GridSplitter()
        item.HorizontalAlignment = HorizontalAlignment.Stretch
        item.VerticalAlignment = VerticalAlignment.Center
        item.ShowsPreview = True
        item.Height = 5
        length = GridLength(width, GridUnitType.Auto)
        self.ctrl.RowDefinitions.Add(RowDefinition(Height = length))
        Grid.SetRow(item, self.rows);
        self.ctrl.Children.Add(item)
        self.rows = self.rows + 1
                 
class WpfHBox():
    def __init__(self):
        self.ctrl = Grid()
        self.ctrl.Margin = Thickness(1)
        self.cols = 0
    def AddItem(self,item,attr=None,width=1):
        if attr and attr.get('expand'): length = GridLength(width, GridUnitType.Star)
        else: length = GridLength(width, GridUnitType.Auto)
        self.ctrl.ColumnDefinitions.Add(ColumnDefinition(Width = length))
        Grid.SetColumn(item, self.cols);
        if attr and attr.get('group'):
            group = GroupBox()
            group.Header = attr['group']
            group.AddChild(item)
            Grid.SetColumn(group, self.cols);
            self.ctrl.Children.Add(group)
        else:
            if attr and attr.get('border') and attr['border']:
                rect = Rectangle()
                rect.Stroke = Brushes.Gray
                rect.Fill = Brushes.Transparent
                Grid.SetColumn(rect, self.cols);
                self.ctrl.Children.Add(rect)
            self.ctrl.Children.Add(item)
        self.cols = self.cols + 1
    def AddSplitter(self,width=1):
        from System.Windows.Controls import GridSplitter
        item = GridSplitter()
        item.HorizontalAlignment = HorizontalAlignment.Center
        item.VerticalAlignment = VerticalAlignment.Stretch
        item.ShowsPreview = True
        item.Width = 5
        length = GridLength(width, GridUnitType.Auto)
        self.ctrl.ColumnDefinitions.Add(ColumnDefinition(Width = length))
        Grid.SetColumn(item, self.cols);
        self.ctrl.Children.Add(item)
        self.cols = self.cols + 1

class WpfBorder():
    def __init__(self):
        self.ctrl = Border()
        self.ctrl.HorizontalAlignment = HorizontalAlignment.Left
        self.ctrl.VerticalAlignment = VerticalAlignment.Top
        self.ctrl.Background = Brushes.SkyBlue
        self.ctrl.BorderBrush = Brushes.Black
        self.ctrl.BorderThickness = Thickness(1)
    def SetChild(self,ctrl):
        self.ctrl.Child = ctrl
        
class WpfStackBox():
    def __init__(self):
        self.ctrl = StackPanel()
        self.ctrl.Margin = Thickness(1)
    def Add(self,item):
        self.ctrl.Children.Add(item)

class WpfGroupBox():
    def __init__(self,h):
        self.ctrl = GroupBox()
        if h.get('label'): self.ctrl.Header = h['label']
        if h.get('item'):
            self.AddItem(WpfLayout(h['item']))   
    def AddItem(self,item):
        self.ctrl.AddChild(item)
        
class WpfTabPane():
    def __init__(self,h):
        self.ctrl = TabControl()
        self.ctrl.Margin =  System.Windows.Thickness(15)
        labels = h.get('labels')
        items = h.get('items')
        if labels and items:
            for i in range(0,len(items)):
                self.AddItem( labels[i], WpfLayout(items[i]))  
    def AddItem(self,label,layout):
        tab = TabItem()
        tab.Header = label
        tab.Content = layout
        self.ctrl.Items.Add(tab)

class WpfHSplitPane():
    def __init__(self,h):
        self.box = WpfHBox()
        self.ctrl = self.box.ctrl
        self.ctrl.Margin = Thickness(1)
        items = h.get('items')
        width = [ 1, 1 ]
        if h.get('first'):
            width[0] = float(h['first']) * 10
            width[1] = 10 - width[0] 
        self.box.AddItem(WpfLayout(items[0]),{'expand':True},width[0])
        self.box.AddSplitter()
        self.box.AddItem(WpfLayout(items[1]),{'expand':True},width[1])  

class WpfVSplitPane():
    def __init__(self,h):
        self.box = WpfVBox()
        self.ctrl = self.box.ctrl
        self.ctrl.Margin =  System.Windows.Thickness(1)
        items = h.get('items')
        height = [ 1, 1 ]
        if h.get('first'):
            height[0] = float(h['first']) * 10
            height[1] = 10 - height[0] 
        self.box.AddItem(WpfLayout(items[0]),{'expand':True},height[0])
        self.box.AddSplitter()
        self.box.AddItem(WpfLayout(items[1]),{'expand':True},height[1])  

class WpfMenu():
    def __init__(self,name,menu_table):
        self.ctrl = MenuItem()
        self.ctrl.Header = name;        
        for m in menu_table:
            if not m.get('name') or m['name'] == '-':
                self.ctrl.Items.Add(Separator())
                continue
            if not m.get('item'): continue # Disabled
            if type(m['item']) == list:
                self.ctrl.Items.Add(WpfMenu(m['name'],m['item']).ctrl)
            else:
                item = MenuItem()
                if m.get('name'): item.Header = m['name']
                if m.get('image'):
                    image = Image()
                    image.Source = BitmapImage(System.Uri(m['image'],System.UriKind.Relative))
                    item.Icon = image
                if m.get('item'): item.Click += m['item']
                if m.get('tooltip'): 
                    tooltip =  ToolTip()
                    tooltip.Content = m['tooltip']
                    item.ToolTip = tooltip
                self.ctrl.Items.Add(item)

def WpfMenuBar(menu_table):
    ctrl = Menu()
    ctrl.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
    ctrl.VerticalAlignment = System.Windows.VerticalAlignment.Top;
    for m in menu_table:
        ctrl.Items.Add(WpfMenu(m['name'],m['item']).ctrl) 
    return ctrl

def WpfToolBar(tool_table):
    tray = ToolBarTray()
    for v in tool_table:
        ctrl = ToolBar()
        ctrl.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
        ctrl.VerticalAlignment = System.Windows.VerticalAlignment.Bottom;
        for h in v:
            name  = h['name']
            f = None
            if   name == 'Label': f = WpfLabel(h)
            elif name == 'Button': f = WpfButton(h)     
            elif name == 'ToggleButton': f = WpfToggleButton(h)
            elif name == 'CheckBox': f = WpfCheckBox(h)
            elif name == 'TextField': f = WpfTextBox(h)
            elif name == 'ChoiceBox': f = WpfChoiceBox(h)
            elif name == 'ComboBox': f = WpfComboBox(h)
            elif name == 'ProgressBar': f = WpfProgressBar(h)
            elif name == 'DatePicker': f = WpfDatePicker(h)
            elif name == 'Slider': f = WpfSlider(h)
            if f: ctrl.Items.Add(f.ctrl)
        tray.AddChild(ctrl)
    return tray

def WpfStatusBar(status_table):
    ctrl = StatusBar()
    ctrl.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
    ctrl.VerticalAlignment = System.Windows.VerticalAlignment.Bottom;
    for h in status_table:
        if h.get('name'):
            name  = h['name']
            if   name == 'Label': f = WpfLabel(h)
            elif name == 'Button': f = WpfButton(h)
            elif name == 'ToggleButton': f = WpfToggleButton(h)
            elif name == 'CheckBox': f = WpfCheckBox(h)
            elif name == 'TextField': f = WpfTextBox(h)
            elif name == 'ChoiceBox': f = WpfChoiceBox(h)
            elif name == 'ComboBox': f = WpfComboBox(h)
            elif name == 'ProgressBar': f = WpfProgressBar(h)
            elif name == 'DatePicker': f = WpfDatePicker(h)
            elif name == 'Slider': f = WpfSlider(h)
            item = StatusBarItem()
            item.Content = f.ctrl        
            ctrl.Items.Add(item)
    return ctrl

def WpfLayout(content):
    vbox = WpfVBox()
    for v in content:
        hbox = WpfHBox()
        attr = None
        for h in v:
            name = h.get('name')
            if not name:
                attr = h
            else:
                if   name == 'Spacer': f = WpfSpacer(h)
                elif name == 'Label': f = WpfLabel(h)
                elif name == 'ImageView': f = WpfImageView(h)
                elif name == 'Button': f = WpfButton(h)
                elif name == 'ToggleButton': f = WpfToggleButton(h)
                elif name == 'CheckBox': f = WpfCheckBox(h)
                elif name == 'TextField': f = WpfTextBox(h)
                elif name == 'ChoiceBox': f = WpfChoiceBox(h)
                elif name == 'ComboBox': f = WpfComboBox(h)
                elif name == 'ProgressBar': f = WpfProgressBar(h)
                elif name == 'DatePicker': f = WpfDatePicker(h)
                elif name == 'Slider': f = WpfSlider(h)
                elif name == 'TextArea': h['multiline'] = True; f = WpfTextBox(h)
                elif name == 'ListBox': f = WpfListBox(h)
                elif name == 'TreeView': f = WpfTreeView(h)
                elif name == 'TableView': f = WpfTableView(h)
                elif name == 'WebView': f = WpfWebView(h)
                elif name == 'GroupBox': f = WpfGroupBox(h)
                elif name == 'TabPane': f = WpfTabPane(h)
                elif name == 'HSplit': f = WpfHSplitPane(h)
                elif name == 'VSplit': f = WpfVSplitPane(h)
                else: continue
                hbox.AddItem(f.ctrl,h)
            '''
            elif name == 'ScrollImageView': f = WpfScrollImageView(h,parent)
            elif name == 'ProgressBar': f = WpfProgressBar(h)
            '''            
        vbox.AddItem(hbox.ctrl,attr)
    return vbox.ctrl

#
# API
#

#
# Thread, Execute
#

'''
def RunLater(handler):
    from System import Action
    System.Windows.Threading.DispatcherExtensions.BeginInvoke(
        System.Windows.Threading.Dispatcher.CurrentDispatcher, Action(handler))
'''

def RunLater(ctrl,handler):
    ctrl.Dispatcher.BeginInvoke(System.Action(handler))

def Execute(cmd):
    import subprocess
    try:
        out = subprocess.check_output(cmd)
        return 0,out
    except:
        return -1,""
                
def StartTimer(handler,msec):
    aTimer = System.Timers.Timer(msec)
    aTimer.Elapsed += GetHandler(handler)
    aTimer.AutoReset = True
    #aTimer.Enabled = True
    aTimer.Start()
    #aTimer.Stop();
    #aTimer.Dispose();
           
def StartThread(handler):
    import threading
    thread = threading.Thread(target=handler)
    thread.daemon = True
    thread.start()

def StartTask(handler):
    Task.Factory.StartNew(handler) 

#
# File Drop
#

def DragEnter(sender, event):
    if event.Data.GetDataPresent(DataFormats.FileDrop):
        event.Effect = DragDropEffects.All
    else:
        event.Effect = DragDropEffects.None

def DragOver(sender, event):
    if event.Data.GetDataPresent(DataFormats.FileDrop):
        event.Effect = DragDropEffects.Copy
    
def DragDropped(handler):
    def DropHandler(sender, event):
        if event.Data.GetDataPresent(DataFormats.FileDrop):
            files = event.Data.GetData(DataFormats.FileDrop)
            handler(files)
    return DropHandler
    
def SetFileDropHandler(ctrl,handler):
    ctrl.AllowDrop = True 
    #ctrl.DragEnter += DragEnter
    #ctrl.DragOver += DragOver
    ctrl.Drop += DragDropped(handler)

#
# Clipboard
#

def ClipboardGetTextData():
    return Clipboard.GetData(DataFormats.Text)

def ClipboardSetTextData(text):
    Clipboard.SetData(DataFormats.Text, text)

def ClipboardGetHtmlData():
    return Clipboard.GetData(DataFormats.Html)

def ClipboardSetHtmlData(text):
    Clipboard.SetData(DataFormats.Html, text)

def ClipboardGetText():
    return Clipboard.GetText()

def ClipboardSetText(text):
    Clipboard.SetText(text)
       

#
# Dialog
#

def WpfAlertDialog(message,title=None):
    if title: MessageBox.Show(message,title)
    else: MessageBox.Show(message)

def WpfYesNoDialog(message,title,icon=System.Windows.MessageBoxImage.Information):
    rv = MessageBox.Show(message,title,MessageBoxButton.YesNo,icon)
    if rv == MessageBoxResult.Yes: return True
    else: return False

def WpfYesNoCancelDialog(message,title,icon=System.Windows.MessageBoxImage.Information):
    rv = MessageBox.Show(message,title,MessageBoxButton.YesNoCancel,icon)
    if rv == MessageBoxResult.Yes: return True
    elif rv == MessageBoxResult.No: return False
    else: return None
    
def WpfFileOpenDialog(initialFile=None,multiselect=False):
    dlg = OpenFileDialog()
    dlg.Multiselect = multiselect
    dlg.DefaultExt = ".txt"; # Default file extension
    dlg.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*";
    if initialFile:
        dlg.InitialDirectory = System.IO.Path.GetDirectoryName(initialFile)
        dlg.FileName = System.IO.Path.GetFileName(initialFile)
        #Directory.GetParent(initialFile) #Path.GetFileName(initialFile)
    if dlg.ShowDialog() == True:
        return dlg.FileNames 

def WpfFileSaveDialog(initialFile=None):
    dlg = SaveFileDialog()
    dlg.DefaultExt = ".txt"; # Default file extension
    dlg.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*";
    if initialFile:
        dlg.InitialDirectory = System.IO.Path.GetDirectoryName(initialFile)
        dlg.FileName = System.IO.Path.GetFileName(initialFile)
    if dlg.ShowDialog() == True:
        return dlg.FileNames 

def WpfDirectoryOpenDialog(initialDirectory=None):
    dlg = FolderBrowserDialog()
    dlg.ShowNewFolderButton = True
    if initialDirectory:
        dlg.SelectedPath = initialDirectory #Path.GetFileName(initialFile)
    if dlg.ShowDialog() != DialogResult.Cancel:
        return dlg.SelectedPath 

#
# Window
#

class WpfWindow(Window):  
    def __init__(self,title="",width=800,height=600):
        print('WpfWindow.__init__()')
        self.ctrl = None
        self.stage = None
        self.createdHandler = None
        self.closeHandler = None
        self.title = None
        self.icon = None
        self.width = 800
        self.height = 600
        self.menu = None
        self.tool = None
        self.status = None
        self.content = None
    def Popup(self):
        self.box = WpfVBox()
        if self.menu: self.box.AddItem(WpfMenuBar(self.menu),{'expand':False})
        if self.tool: self.box.AddItem(WpfToolBar(self.tool),{'expand':False})
        if self.content: self.box.AddItem(WpfLayout(self.content),{'expand':True})
        if self.status: self.box.AddItem(WpfStatusBar(self.status),{'expand':False})
        self.Content = self.box.ctrl
        if self.createdHandler: self.createdHandler()
        self.Show()
    def Run(self):
        self.Popup()
        Application().Run(self) 
    def SetTitle(self,title): self.Title = title
    def SetSize(self,width,height): self.Width = width; self.Height = height
    def SetIcon(self,icon): self.Icon = BitmapFrame.Create(System.Uri(icon, System.UriKind.RelativeOrAbsolute))
    def SetMenuBar(self,menu): self.menu = menu
    def SetToolBar(self,tool): self.tool = tool
    def SetStatusBar(self,status): self.status = status
    def SetContent(self,content): self.content = content
    def SetCreatedHandler(self,handler): self.createdHandler = handler
    def SetCloseHandler(self,handler): self.Closing += GetHandler(handler)
    def SetFileDropHandler(self,handler): SetFileDropHandler(self,handler)

#
# Application
#

def onExit(event):
    System.Windows.Application.Current.Shutdown();
def onAbout(event):
    WpfAlertDialog("Hello, world!", "My App");
def printText(text):
    ctrl = GetControl('textarea')
    if ctrl:
        ctrl.AppendText(text + '\n')
        ctrl.ScrollToEnd()
def onChoice(event):
    ctrl = GetControl('choice')
    if ctrl: printText("Selected: " + ctrl.GetAddedItem(event.args) + "\n")
def onCheck(event):
    ctrl = GetControl('check')
    if ctrl: printText("Checked: " + ctrl.GetValue().ToString() + "\n")
def onListBox(event):
    ctrl = GetControl('listbox')
    if ctrl: printText("List Selected: " + ctrl.GetValue().ToString() + "\n")
def onListView(event): #event
    ctrl = GetControl('listbox')
    listview = GetControl('table')
    #row = listview.GetValue()
    #printText(row['col1'] + "," + row['col2'])
    rows = listview.GetSelectedItems()
    for row in rows:
        printText(row['Name'] + "," + row['Age'])
        
def onBrowse(event):
    ctrl = GetControl('textfile')
    files = WpfFileOpenDialog()
    if files: ctrl.SetValue(files[0])
def onBrowseFolder(event):
    ctrl = GetControl('textfile')
    folder = WpfDirectoryOpenDialog()
    if folder: ctrl.SetValue(folder)
def onToggle(event):
    ctrl = GetControl('toggle')
    if ctrl: printText('Toggle: ' + str(ctrl.IsSelected()))
def onDatePicker(event):
    ctrl = GetControl('datepicker')
    if ctrl: printText('Date: ' + str(ctrl.GetValue()))
def onSlider(event):
    ctrl = GetControl('slider')
    if ctrl: printText('Slider: ' + str(ctrl.GetValue()))
def onTreeView(event):
    ctrl = GetControl('tree')
    if ctrl: printText('Treeview: ' + str(ctrl.GetSelectedItemPath('/')))
def onRun(event):
    text = GetControl('textfile')
    print(text.GetValue())
    if text:
        rv, out = Execute(text.GetValue())
        textarea = GetControl('textarea')
        textarea.SetValue(str(rv) + '\n' + out)

progress_value = 0

def threadHandler():
    global progress_value
    import time
    label = GetControl('status')
    for i in range(100):
        progress_value += 1
        RunLater(label.ctrl, lambda : label.SetValue(str(i)))
        time.sleep(0.1)

def taskHandler():
    import time
    prog = GetControl('progress')
    for i in range(100):
        RunLater(prog.ctrl, lambda : prog.SetValue(i))
        time.sleep(0.1)

def timerHandler(event):
    global progress_value
    print(progress_value)

def onFileDrop(files):
    print('onFileDrop',files)
    ctrl = GetControl('textfile')
    ctrl.SetValue(files[0])

def onTableDrop(files):
    print('onFileDrop',files)
    ctrl = GetControl('textfile')
    ctrl.SetValue(files[0])
    
def onCreated():
    #SetFileDropHandler(GetControl('textfile').ctrl,onFileDrop)
    listview = GetControl('table')
    listview.AddItem( { "Name":"Anny" , "Age":"18" } )
    listview.AddItem( { "Name":"Bobby", "Age":"16" } )
    listview.AddItem( { "Name":"Candy", "Age":"14" } )
    tree = GetControl('tree')
    item = tree.AddRootItem("Item1")
    tree.AddItem("Item1-1",item)
    tree.AddItem("Item1-2",item)
    item = tree.AddRootItem("Item2")
    tree.AddItem("Item2-1",item)
    tree.AddItem("Item2-2",item)
    StartTimer(timerHandler,1000)
    StartThread(threadHandler)
    StartTask(taskHandler)

def onClosing(event):
    if not WpfYesNoDialog("Do you want to quie ?","Quit"):
        event.args.Cancel = True

def onOK(event):
    win = MakeWindow()
    win.Popup()
    
app_mainmenu = [
    { 'name' : "File",
      'item' : [
            { 'name' : "Exit" , 'item' : onExit, 'image' : 'icon/folder512.png', 'tooltip' : 'Exit Program' },
            { 'name' : "-" ,  },
            { 'name' : "About" , 'item' : onAbout, 'image' : 'exit.png' } ]
    }, { 'name' : "Help",
      'item' : [
            { 'name' : "About", 'item' : onAbout, 'check' : True, 'image' : 'new.png' } ]
    }]
app_tool = [[
        { "name" : "Button", "label" : "Click", "image" : "./icon/folder512.png", 'size' : 16  },
    ],[
        { "name" : "ChoiceBox", "items" : [ "apple", "grape" ], 'key' : 'choicetool', 'handler' : onChoice },
        { "name" : "ComboBox", "items" : [ "apple", "grape" ] },
        { "name" : "Label", "label" : "Address:", "menu" : app_mainmenu },
        { "name" : "TextField", "key" : "textfile", 'width' : 40 },
        { "name" : "Button", 'handler' : onBrowse, "label" : "Browse", "tooltip" : "About this program" },
        { "name" : "ToggleButton", "label" : "Toggle", 'key' : 'toggle', 'handler' : onToggle },
    ], 
]
app_status = [
        { "name" : "ProgressBar", 'key' : 'progress' },
        { "name" : "Slider", 'key' : 'slider', 'handler' : onSlider },
        { "name" : "Label", "label" : "Ready", 'key' : 'status' },
        { "name" : "Button", "label" : "Click" },
    ]
    
tab1 = [[ { "name" : "WebView", "key" : "webview", "expand" : True, "toolbar" : True, "uri" : "http://google.co.kr" },
        { 'expand' : True } ]]
tab2 = [[ { "name" : "ListBox", "items" : [ "apple", "grape" ], 'expand' : True, 'key' : 'listbox', 'handler' : onListBox },
        { 'expand' : True } ]]
tab3 = [[ { "name" : "TableView", "columns" : [ "Name", "Age" ], 'widths' : [ 100, 200 ], 'expand' : True, 'key' : 'table', 'handler' : onListView, 'menu' : app_mainmenu, 'drop' : onTableDrop },
        { 'expand' : True } ]]
tab4 = [[ { "name" : "TreeView", "key" : "tree", 'handler' : onTreeView,"expand" : True },
          { "expand" : True }, ]]
tab5 = [[ { "name" : "ImageView", 'image' : "Lenna.png", "stretch" : "uniform", "scroll" : True, "expand" : True },
          { "expand" : True }, ]]
split1 = [[
        { "name" : "TabPane", "labels" : [ "Web", "List", "Table", "Tree", "Image" ], "items" : [ tab1, tab2, tab3, tab4, tab5 ], "expand" : True },
        { "expand" : True }, ]]
split2 = [[ { "name" : "TextArea", 'key' : 'textarea', "expand" : True, 'toolbar' : True },
            { "expand" : True }, ]]

app_content = [ # vbox
    [ # hbox
        { "name" : "GroupBox" , 'label': "Tool2", 'item' : [[
            { "name" : "Label", "label" : "Address:", "menu" : app_mainmenu },
            { "name" : "TextField", "key" : "textfile", "expand" : True, "menu" : app_mainmenu },
            { "name" : "Button", 'handler' : onBrowse, "label" : "File", "tooltip" : "About this program" },
            { "name" : "Button", 'handler' : onBrowseFolder, "label" : "Folder", "tooltip" : "About this program" },
            { "name" : "Button", 'handler' : onRun, "label" : "Run", "tooltip" : "Execute Command" },
        ]], 'expand' : True }
    ],
    [ # hbox
        { "name" : "ChoiceBox", "items" : [ "apple", "grape" ], 'key' : 'choice', 'handler' : onChoice },
        { "name" : "ComboBox", "items" : [ "apple", "grape" ] },
        { "name" : "CheckBox", "label" : "Click Me", 'key' : 'check', 'handler' : onCheck },
        { "name" : "ToggleButton", "label" : "Toggle", 'key' : 'toggle', 'handler' : onToggle },
        { "name" : "DatePicker", "label" : "Toggle", 'key' : 'datepicker', 'handler' : onDatePicker },
        { 'group' : "Tools" },
    ],     
    [ # hbox
        { "name" : "HSplit", "items" : [ split1, split2 ] , "first" : 0.5, "expand" : True, 'border' : False},
        { "expand" : True, 'border' : True  },
    ],     
    [ # hbox
        { "name" : "Spacer",  },
        { "name" : "Button", "label" : "OK", 'width' : 64, 'height' : 24, 'handler' : onOK },
        { "name" : "Spacer", 'width' : 8 },
    ],     
]

def MakeWindow():
    win = WpfWindow()
    win.SetTitle("PyWPF")
    #win.SetIcon("./icon/Lenna.png")
    win.SetSize(640,400)
    win.SetMenuBar(app_mainmenu)
    win.SetToolBar(app_tool)
    win.SetStatusBar(app_status)
    win.SetContent(app_content)
    win.SetCreatedHandler(onCreated)  
    win.SetCloseHandler(onClosing)
    win.SetFileDropHandler(onFileDrop)
    return win

if __name__ == "__main__":
    global appWin
    appWin = MakeWindow()
    appWin.Run()

댓글 없음:

댓글 쓰기