2021년 2월 2일 화요일

[IronPython] WPF Library

1. WPF Wrapper Library
import clr
clr.AddReference("PresentationFramework")
clr.AddReference("PresentationCore");
clr.AddReference('WindowsBase')
clr.AddReference('System.Data')
clr.AddReference('System.ComponentModel')
clr.AddReference('System.Windows.Forms')
#clr.AddReference("System.Drawing")

import System
from System import *
from System.Data import *
from System.Type import GetType
from System.Threading.Tasks import Task
from System.ComponentModel import *
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 *
from System.Windows.Ink import Stroke
from System.Windows.Input import * 
from Microsoft.Win32 import ( OpenFileDialog, SaveFileDialog )
#from System.Drawing import * 


'''
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
'''

import wpf_icon

#
# API
#

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

class Class:
    def __init__(self,**kwargs): self.__dict__.update(kwargs)
    
def GetHandler(handler):
    return lambda s,e: handler(Class(sender=s,event=e))
    '''
    def Handler(sender,args):
        handler(Class(sender=sender,args=args))
    return Handler
    '''
    
def StartTimer(handler,msec):
    tmr = System.Timers.Timer(msec)
    tmr.Elapsed += handler
    tmr.AutoReset = True
    #tmr.Enabled = True
    tmr.Start()
    #tmr.Stop();
    #tmr.Dispose();
    
def StartTask(handler):
    Task.Factory.StartNew(handler) 

def Delay(msec):
    #Thread.Sleep() make GUI stuck
    ThisMoment = DateTime.Now;
    duration = TimeSpan(0, 0, 0, 0, msec);
    AfterWards = ThisMoment.Add(duration);
    while AfterWards >= ThisMoment:
        System.Windows.Forms.Application.DoEvents()
        ThisMoment = DateTime.Now
    return DateTime.Now;

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)
    
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)

def FileExists(filename):
    return System.IO.File.Exists(filename)

def FileSize(filename):
    fi = System.IO.FileInfo(filename)
    return fi.Length

def GetParent(filename):
    return System.IO.Path.GetDirectoryName(filename)

def GetBitmapFrame(bytearray):
    return BitmapFrame.Create(
            System.IO.MemoryStream(bytearray), 
            BitmapCreateOptions.None, 
            BitmapCacheOption.OnLoad)

def file_to_base64(filename):
    with open(filename,"rb") as f:
        data = bytes(f.read()).ToByteArray()
        return Convert.ToBase64String(data)

def base64_to_file(filename,data):
    with open(filename,"wb") as f:
        byteArray = Convert.FromBase64String(data);
        f.write(bytes(byteArray))

def GetImageSource(image): 
    return GetBitmapFrame(image)

def GetImage(image, size=None, width=None, height=None): 
    img = Image()
    img.Source = GetBitmapFrame(image)
    if size: img.Width = size; img.Height = size
    if width: img.Width = width
    if height: img.Height = height
    return img

def GetKey(event):
    if event.Key == Key.Right: return 'right'
    if event.Key == Key.Left: return 'left'

def ByteArray(zname):
    return bytes(zname).ToByteArray()

def pyZipToImageSource(data):
    return GetBitmapFrame(bytes(data).ToByteArray())

def getTextBlock(text,align=0):
    ctrl = TextBlock()
    ctrl.Text = text
    if align == 0: ctrl.TextAlignment = TextAlignment.Center    
    elif align < 0: ctrl.TextAlignment = TextAlignment.Left 
    elif align > 0: ctrl.TextAlignment = TextAlignment.Right
    return ctrl   
    
#
# Controls
#

class WpfCtrl():
    def init(self):
        self.ctrl.Margin  = Thickness(5)
        self.ctrl.Padding = Thickness(1)
    def enable(): self.ctrl.IsEnabled = True
    def disable(): self.ctrl.IsEnabled = False
    def show(): self.ctrl.Visibility = Visibility.Visible
    def hide(): self.ctrl.Visibility = Visibility.Hidden
    def remove(): self.ctrl.Visibility = Visibility.Collapsed
    def is_shown(): return self.ctrl.IsVisible
    def set_width(self,v): self.ctrl.Width = v
    def set_height(self,v): self.ctrl.Height = v
    def set_margin(self,l,t,r,b): self.ctrl.Margin = System.Windows.Thickness(l,t,r,b)
    def shadow_effect(self):
        from System.Windows.Media.Effects import DropShadowBitmapEffect
        self.ctrl.BitmapEffect = DropShadowBitmapEffect()
    def set_fontsize(self,size):
        self.ctrl.FontSize = size
    def set_tooltip(self,tooltip):
        tip = ToolTip()
        tip.Content = tooltip
        self.ctrl.ToolTip = tip
    def set_menu(self,menu_table):
        menu = ContextMenu()
        for m in menu_table:
            menu.Items.Add(WpfMenu(m['name'],m['item']).ctrl)         
        self.ctrl.ContextMenu = menu
    def set_filedrop(self,handler):
        SetFileDropHandler(self.ctrl,handler)
        
class WpfButton(WpfCtrl):
    def __init__(self,text=None,handler=None,image=None,imagefile=None,size=None,width=None,height=None,vert=True,**kwargs):
        self.ctrl = Button()
        self.init(**kwargs)
        stack = StackPanel()
        if vert: stack.Orientation = Orientation.Vertical
        else: stack.Orientation = Orientation.Horizontal
        self.ctrl.Content = stack
        if width: self.ctrl.Width = width
        if height: self.ctrl.Height = height
        if image:
            stack.Children.Add(self.get_image(image))
        if imagefile:
            image = self.get_image(BitmapImage(System.Uri(imagefile,System.UriKind.Relative)))
            stack.Children.Add(self.get_image(image))
        if text: 
            txt = TextBlock()
            txt.Text = text
            txt.TextAlignment = TextAlignment.Center
            stack.Children.Add(txt)         
        if handler: self.ctrl.Click += handler
    def get_image(self,img):
        img.VerticalAlignment = VerticalAlignment.Center
        img.Stretch = Stretch.Fill #Stretch.None
        return img
        
class WpfCheck(WpfCtrl):
    def __init__(self,text=None,handler=None,**kwargs):
        self.ctrl = CheckBox()
        self.ctrl.VerticalAlignment = VerticalAlignment.Center
        self.ctrl.VerticalContentAlignment = VerticalAlignment.Center
        self.init(**kwargs)
        if text: self.ctrl.Content = text
        if handler: self.ctrl.Click += handler        
    def get_value(self): return self.ctrl.IsChecked
    def GetSelectedItem(self): return self.ctrl.SelectedItem

class WpfChoice(WpfCtrl):
    def __init__(self,items=None,handler=None,selected=0,size=None,width=None,height=None,**kwargs):
        self.ctrl = ComboBox()
        self.init(**kwargs)
        if handler: self.ctrl.SelectionChanged += handler
        if items:
            self.ctrl.ItemsSource = items
            self.ctrl.SelectedIndex = selected     
        if width: self.ctrl.Width = width
        if height: self.ctrl.Height = height
    def get_value(self): return self.ctrl.Text
    def get_added_item(self,args): return args.AddedItems[0]
    def get_selected_index(self): return self.ctrl.SelectedIndex
    def get_selected_item(self): return self.ctrl.SelectedItem
    def get_selected_text(self): return self.ctrl.SelectedItem.ToString()
    def set_height(self,v): pass
    def set_selected_index(self,index): self.ctrl.SelectedIndex = index
    def add_item(self,text): self.ctrl.Items.Add(text)
    
class WpfCombo(WpfCtrl):
    def __init__(self,items=None,handler=None,selected=0,size=None,width=None,height=None,**kwargs):
        self.ctrl = ComboBox()
        self.ctrl.IsEditable=True
        self.ctrl.IsReadOnly=False        
        self.init(**kwargs)
        if handler: self.ctrl.SelectionChanged += handler
        if items:
            self.ctrl.ItemsSource = items
            self.ctrl.SelectedIndex = selected     
        self.ctrl.Height = 22
        if width: self.ctrl.Width = width
        if height: self.ctrl.Height = height
    def get_value(self): return self.ctrl.Text
    def get_added_item(self,args): return args.AddedItems[0]
    def get_selected_item(self): return self.ctrl.SelectedItem
    def get_selected_text(self): return self.ctrl.SelectedItem.ToString()
    def set_height(self,v): pass

class WpfDate(WpfCtrl):
    def __init__(self,handler=None,**kwargs):   
        self.ctrl = DatePicker()
        self.init(**kwargs)
        if handler: self.ctrl.SelectedDateChanged += handler
    def get_value(self):
        return self.ctrl.Text
    def set_value(self,v):
        self.ctrl.Text = v

class WpfEdit(WpfCtrl):
    def __init__(self,text=None,multiline=True,tool=False,handler=None,image=None,size=None,vert=True,**kwargs):
        self.text = TextBox()
        self.ctrl = self.text
        self.init(**kwargs)
        if multiline: 
            self.ctrl.AcceptsReturn = True
            self.ctrl.AcceptsTab = True
            self.ctrl.TextWrapping = TextWrapping.NoWrap
            self.ctrl.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto
            self.ctrl.VerticalScrollBarVisibility   = ScrollBarVisibility.Auto
        else:
            self.ctrl.Height = 22
        if handler: self.ctrl.Click += handler
        if tool:
            self.vbox = vbox.WpfVBox()
            self.hbox = hbox.WpfHBox()
            self.hbox.add_item(self.get_button("Clear", self.clear_handler))
            self.hbox.add_item(self.get_button("Copy", self.copy_handler))
            self.hbox.add_item(self.get_button("CopyAll", self.copy_all_handler))
            self.hbox.add_item(self.get_button("Paste", self.paste_handler))
            self.hbox.add_item(self.get_button("PasteHtml", self.paste_html_handler))
            self.vbox.add_item(self.hbox.ctrl)
            self.vbox.add_item(self.text,expand=True)
            self.ctrl = self.vbox.ctrl

    def set_height(self,v): pass
    def clear(self): self.text.Text = ""
    def get_value(self): return self.text.Text
    def set_value(self,text): self.text.Text = text
    def append_text(self,text): self.text.Text += text
    def set_width(self,width): self.text.Width = width
    def scroll_to_end(self): self.text.ScrollToEnd()
    def set_wrap(self,wrap): self.text.TextWrapping = TextWrapping.Wrap if wrap else TextWrapping.NoWrap
    def get_button(self,label,handler): b = Button(); b.Content = label; b.Click += handler; return b
    def clear_handler(self,sender,args): self.text.Clear()
    def copy_handler(self,sender,args): self.text.Copy()
    def copy_all_handler(self,sender,args): self.text.SelectAll(); self.text.Copy()
    def paste_handler(self,sender,args): self.text.Paste()
    def paste_html_handler(self,sender,args): self.text.Text = ClipboardGetHtmlData()
        
class WpfGroup(WpfCtrl):
    def __init__(self,text=None):
        self.ctrl = GroupBox()
        if text: self.ctrl.Header = text
    def add_item(self,item):
        self.ctrl.AddChild(item)
 
class WpfImage(WpfCtrl):
    def __init__(self,imagefile=None,image=None,stretch=None,scroll=True,multiple=False,**kwargs):
        self.image = self.ctrl = Image()
        self.scroll = None
        self.pos = None
        #self.init(**kwargs)
        #self.image.HorizontalAlignment = HorizontalAlignment.Stretch #Center
        #self.image.VerticalAlignment = VerticalAlignment.Stretch #Center
        if imagefile: self.set_imagefile(imagefile)
        if image: self.set_image(image)
        if stretch: self.stretch(stretch)
        else: self.stretch_uniform()
        '''if size: 
            self.image.Height = float(size); 
            self.image.Width = float(size)'''
        if scroll:
            self.scroll = self.ctrl = ScrollViewer()
            #self.scroll.HorizontalAlignment = HorizontalAlignment.Stretch #Center
            #self.scroll.VerticalAlignment = VerticalAlignment.Stretch #Center
            self.scroll.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto
            #self.scroll.PanningMode = PanningMode.Both
            self.scroll.Content = self.image
        elif multiple:
            self.ctrl = stack = StackPanel()
            stack.Orientation = Orientation.Horizontal
            stack.Children.Add(self.image) 
        self.image.MouseWheel += self.mouse_wheel
        self.image.MouseLeftButtonDown += self.mouse_down
        self.image.MouseLeftButtonUp += self.mouse_up
        self.image.MouseMove += self.mouse_move
    def mouse_wheel(self,s,e): 
        zoom = 1.1 if e.Delta > 0 else 0.9
        self.image.Source.DecodePixelWidth = self.src_width * zoom
        self.set_image(self.image.Source)

        #rect = Rect()
        #rect.Width = self.image.ActualWidth * zoom
        #rect.Height = self.image.ActualHeight * zoom
        #self.image.Arrange(rect)
        #print(self.image.ActualWidth, self.image.ActualHeight)
    def mouse_down(self,s,e): self.pos = e.GetPosition(top_wnd)
    def mouse_up(self,s,e): print( self.image.ActualWidth, self.image.ActualHeight )
    def mouse_move(self,s,e): 
        global top_wnd 
        if e.LeftButton == System.Windows.Input.MouseButtonState.Pressed:
            pos = e.GetPosition(top_wnd)
            if self.pos is None: self.pos = pos
            diff_x = pos.X - self.pos.X
            diff_y = pos.Y - self.pos.Y
            if diff_x != 0 or diff_y != 0:
                if self.scroll:
                    self.scroll.ScrollToHorizontalOffset( self.scroll.HorizontalOffset - diff_x)
                    self.scroll.ScrollToVerticalOffset( self.scroll.VerticalOffset - diff_y)
                else:
                    rect = Rect()
                    rect.X = rect.X + diff_x
                    rect.Y = rect.Y + diff_y
                    rect.Width = self.image.ActualWidth
                    rect.Height = self.image.ActualHeight
                    self.image.Arrange(rect)
                self.pos = pos
    def stretch_none(self): self.image.Stretch = Stretch.None
    def stretch_fill(self): self.image.Stretch = Stretch.Fill
    def stretch_uniform(self): self.image.Stretch = Stretch.Uniform
    def stretch_uniform_to_fill(self): self.image.Stretch = Stretch.UniformToFill
    def stretch(self,stretch):
        if stretch == 'none': self.stretch_none()
        elif stretch == 'fill': self.stretch_fill()
        elif stretch == 'uniform': self.stretch_uniform()
        elif stretch == 'uniformfill': self.stretch_uniform_to_fill()
        else: self.stretch_none()
    def set_image(self,image):
        self.image.Source = image
        self.src_width = self.image.Source.Width
        self.src_height = self.image.Source.Height
    def set_imagefile(self,imagefile):
        self.set_image(BitmapImage(System.Uri(imagefile,System.UriKind.Relative)))
    def scroll_top(self):
        if self.scroll: 
            self.scroll.ScrollToHorizontalOffset(0)
            self.scroll.ScrollToVerticalOffset(0)
        
class WpfLabel(WpfCtrl):
    def __init__(self,text=None,background=None,size=None,width=None,height=None,**kwargs):
        self.ctrl = Label()
        self.init(**kwargs)
        if text: self.ctrl.Content = text
        if background: self.ctrl.Background = background
        self.ctrl.HorizontalAlignment = HorizontalAlignment.Stretch
        self.ctrl.VerticalAlignment = VerticalAlignment.Center   
        if width: self.ctrl.Width = width
        if height: self.ctrl.Height = height
    def set_value(self,text):
        self.ctrl.Content = text

class WpfList(WpfCtrl):
    def __init__(self,items=None,handler=None,selected=0,**kwargs):
        self.ctrl = ListBox()
        self.init(**kwargs)
        if handler: self.ctrl.SelectionChanged += handler
        if items:
            self.ctrl.ItemsSource = items
            self.ctrl.SelectedIndex = selected     
    def get_value(self): return self.get_selected_text()
    def get_selected_item(self): return self.ctrl.SelectedItem
    def get_selected_text(self): return self.ctrl.SelectedItem.ToString()

class WpfProgress(WpfCtrl):
    def __init__(self,value=0,max=100,width=100,height=16,fcolor=None,bcolor=None,**kwargs): 
        self.ctrl = ProgressBar()
        #self.ctrl.IsIndeterminate = True
        #self.ctrl.Margin = new Thickness(10,0,10,10);
        self.init(**kwargs)
        self.ctrl.Visibility = Visibility.Visible;
        self.ctrl.Width = width
        self.ctrl.Height = height
        if fcolor: self.ctrl.Foreground = fcolor  #System.Windows.Media.Brushes.Green
        if bcolor: self.ctrl.Background = bcolor  #System.Windows.Media.Brushes.Red
        #self.ctrl.Style = style if style else ProgressBarStyle.Continuous #Marquee
        self.ctrl.Maximum = max
        self.ctrl.Value = value
        self.ctrl.FlowDirection = FlowDirection.LeftToRight
    def get_value(self):
        return self.ctrl.Value
    def set_value(self,v):
        self.ctrl.Value = v

class WpfSlider(WpfCtrl):
    def __init__(self,handler=None,min=None,max=None,value=None,**kwargs):   
        self.ctrl = Slider()
        self.init(**kwargs)
        if handler: self.ctrl.ValueChanged += handler
        self.ctrl.Width = 100;
        self.ctrl.Height = 16;        
        self.ctrl.Minimum = min if min else 0
        self.ctrl.Maximum = max if max else 100     
        self.ctrl.Value = value if value else 0
        self.ctrl.SmallChange = 1
        self.ctrl.LargeChange = 10
        self.ctrl.TickPlacement = TickPlacement.BottomRight
        self.ctrl.TickFrequency = 10
    def get_value(self):
        return self.ctrl.Value
    def set_value(self,v):
        self.ctrl.Value = v
           
class WpfTable(WpfCtrl):
    def __init__(self,handler=None,columns=None,widths=None,**kwargs):
        self.ctrl = ListView()
        self.table = DataTable('table')
        self.cols = []
        self.init(**kwargs)
        if handler: self.ctrl.SelectionChanged += handler
        self.grid = GridView()
        self.grid.AllowsColumnReorder = True; 
        self.grid.ColumnHeaderToolTip = "ListView Column Info";     
        if columns: 
            for i in range(0,len(columns)):
                width = widths[i] if widths else None
                self.add_column(columns[i],width)     
        self.ctrl.View = self.grid
        self.ctrl.ItemsSource = self.table.DefaultView #DataView(self.table)
        self.ctrl.AddHandler(GridViewColumnHeader.ClickEvent, RoutedEventHandler(self.OnColumnHeaderClick))
        self.sort_dir = ListSortDirection.Ascending
        #TODO
        style = Style()
        style.Setters.Add( Setter(ListViewItem.HorizontalContentAlignmentProperty, HorizontalAlignment.Stretch))
        self.ctrl.ItemContainerStyle = style

    def clear(self):
        #k = self.table.Rows.IndexOf(item)
        for k in range(len(self.table.Rows),0,-1):
            self.table.Rows[k-1].Delete() 
        self.table.AcceptChanges()  #RejectChanges()
    def add_columns(self,names):
        for name in names:
            self.add_column(name)
    def add_column(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)
        self.cols.append(name)
    def add_row(self,row):
        if len(self.cols) == len(row):
            item = self.table.NewRow()
            for index in range(len(row)):
                #item[self.cols[index]] = getTextBlock( row[index], 0 )
                item[self.cols[index]] = row[index]
            self.table.Rows.Add(item)        
    def add_items(self,items):
        item = self.table.NewRow()
        if type(items) == dict:
            for key, value in items.items(): 
                item[key] = value
        else:
            for i in range(len(items)): 
                item[i] = items[i] 
        self.table.Rows.Add(item);
    def get_value(self): 
        return self.ctrl.SelectedItem
    def get_selected_items_org(self): 
        return self.ctrl.SelectedItems
    def get_selected_items(self): 
        items = []
        for row in self.ctrl.SelectedItems:
            item = []
            for col in self.cols:
                item.append(row[col])
            items.append(item)
        return items
    def get_all_items(self): 
        items = []
        for row in self.ctrl.Items:
            item = []
            for col in self.cols:
                item.append(row[col])
            items.append(item)
        return items     
    def get_column_items(self,col): 
        items = []
        for row in self.ctrl.Items:
            items.append(row[col])
        return items  
    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 column_sort(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.column_sort( columnBinding.Path.Path, self.sort_dir ) #headerClicked.Column.Header

class WpfToggle(WpfCtrl):
    def __init__(self,text=None,handler=None,image=None,size=None,vert=True,**kwargs):
        self.ctrl = ToggleButton()
        self.init(**kwargs)
        stack = StackPanel()
        if vert: stack.Orientation = Orientation.Vertical
        else: stack.Orientation = Orientation.Horizontal
        self.ctrl.Content = stack
        if image:
            img = Image()
            img.Source = BitmapImage(System.Uri(image,System.UriKind.Relative))
            img.VerticalAlignment = VerticalAlignment.Center
            img.Stretch = Stretch.Fill #Stretch.None
            if size: img.Width = size; img.Height = size
            stack.Children.Add(img)
        if text: 
            txt = TextBlock()
            txt.Text = text
            txt.TextAlignment = TextAlignment.Center
            stack.Children.Add(txt)         
        if handler: self.ctrl.Click += handler
    def get_value(self): return self.ctrl.IsChecked    

class WpfTree(WpfCtrl):
    def __init__(self,name="root",handler=None,**kwargs):
        self.root = TreeViewItem()
        self.root.Header = name
        self.root.IsExpanded = True
        self.ctrl = TreeView()
        self.ctrl.Items.Add(self.root)
        self.init(**kwargs)
        if handler: self.ctrl.SelectedItemChanged  += handler
    def add_root_item(self,label):
        return self.add_item(label)
    def add_item(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 get_selected_item(self):
        return self.ctrl.SelectedItem
    def get_selected_item_text(self):
        return self.ctrl.SelectedItem.Header.ToString()
    def get_selected_item_path(self,delim=""):
        item = self.ctrl.SelectedItem
        return self.get_item_path(item,delim)
    def get_item_path(self,item,delim=""):
        path = item.Header.ToString()
        while type(item.Parent) == TreeViewItem:
            item = item.Parent
            path = item.Header.ToString() + delim + path
        return path
    def get_parent_item(self,item):
        return item.Parent
    def get_item_value(self,item):
        return item.Header.ToString()

class WpfWeb():
    def __init__(self,url=None,tool=False):
        self.web = WebBrowser()
        self.ctrl = self.web
        self.web.Navigated += self.loaded_hndler
        if tool:
            self.vbox = vbox.WpfVBox()
            self.hbox = hbox.WpfHBox()
            self.text = TextBox()
            self.hbox.add_item(self.button("<-", self.back_handler))
            self.hbox.add_item(self.button("->", self.forward_handler))
            self.hbox.add_item(self.button("<>", self.refresh_handler))
            self.hbox.add_item(self.text, {'expand':True})
            self.hbox.add_item(self.button("Go", self.go_Handler))
            self.vbox.add_item(self.hbox.ctrl)
            self.vbox.add_item(self.web,expand=True)
            self.ctrl = self.vbox.ctrl
        if url: self.go(url)
    def button(self,label,handler): b = Button(); b.Content = label; b.Click += handler; return b
    def loaded_hndler(self,sender,args): self.text.Text = self.web.Source.ToString()
    def go_Handler(self,sender,args):
        uri = self.text.Text
        if not uri.startswith('http'): uri = "http://" + uri; self.text.Text = uri
        self.Go(uri)
    def back_handler(self,sender,args): self.back()
    def forward_handler(self,sender,args): self.forward()
    def refresh_handler(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
       
#
# Containers
#

class WpfLayout():
    def add_separater(self,parent=None):
        self.add_item(Separator())
    def add_label(self,text):
        label = Label()
        label.Content = text
        self.add_item( label )    
    def add_button(self,text,handler=None):
        button = Button()
        button.Content = text
        if handler: button.Click += handler
        self.add_item( button )   
        
class WpfGrid():
    def __init__(self,row=None,col=None):
        self.ctrl = Grid()
    def add_row(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 add_column(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 add_item(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 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 = Thickness(2)
        #self.ctrl.Content = self.grid
    def add_row(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 add_column(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 add_item(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 WpfHBox(WpfLayout):
    def __init__(self):
        self.ctrl = Grid()
        self.ctrl.Margin = Thickness(1)
        self.cols = 0
        
    def add_item(self,item,expand=False,group=None,border=False,width=1):
        if expand: length = GridLength(width, GridUnitType.Star)
        else: length = GridLength(width, GridUnitType.Auto)
        self.ctrl.ColumnDefinitions.Add(ColumnDefinition(Width = length))
        Grid.SetColumn(item.ctrl, self.cols);
        if group:
            gbox = GroupBox()
            gbox.Header = group
            gbox.AddChild(item.ctrl)
            Grid.SetColumn(gbox, self.cols);
            self.ctrl.Children.Add(gbox)
        else:
            if 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.ctrl)
        self.cols = self.cols + 1
        
    def add_splitter(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

    def add_spacer(self):
        self.add_item( Label(), expand=True )
        
class WpfHSplit():
    def __init__(self,lsize=1,rsize=1):
        self.box = WpfHBox()
        self.ctrl = self.box.ctrl
        self.box.ctrl.Margin = Thickness(1)
        self.widths = [ lsize, rsize ]
    def add_items(self,items,widths=None):
        if not widths: widths = self.widths
        self.box.add_item(items[0],width=widths[0],expand=True)
        self.box.add_splitter()
        self.box.add_item(items[1],width=widths[1],expand=True)

class WpfTab():
    def __init__(self,items=None):
        self.ctrl = TabControl()
        self.ctrl.Margin =  System.Windows.Thickness(15)
        if items and type(items) == dict:
            for k,v in items.items(): self.add_item( k, v) 
    def add_item(self,label,ctrl):
        tab = TabItem()
        tab.Header = label
        tab.Content = ctrl.ctrl
        self.ctrl.Items.Add(tab)

class WpfVBox(WpfLayout):
    def __init__(self):
        self.ctrl = Grid()
        self.ctrl.Margin = Thickness(1)
        self.rows = 0
    def add_item(self,item,expand=False,border=False,group=None,height=1):
        if expand: length = GridLength(height, GridUnitType.Star)
        else: length = GridLength(height, GridUnitType.Auto)
        self.ctrl.RowDefinitions.Add(RowDefinition(Height = length))
        Grid.SetRow(item.ctrl, self.rows);
        if group:
            gbox = GroupBox()
            gbox.Header = group
            gbox.AddChild(item.ctrl)
            Grid.SetRow(gbox, self.rows);
            self.ctrl.Children.Add(gbox)
        else:
            if 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.ctrl)
        self.rows = self.rows + 1
    def add_splitter(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
    def add_spacer(self):
        self.add_item( Label(), expand=True )

class WpfVSplit():
    def __init__(self,lsize=1,rsize=1):
        self.box = WpfVBox()
        self.ctrl = self.box.ctrl
        self.box.ctrl.Margin = Thickness(1)
        self.heights = [ lsize, rsize ]
    def add_items(self,items,heights=None):
        if not heights: heights = self.heights
        self.box.add_item(items[0],height=heights[0],expand=True)
        self.box.add_splitter()
        self.box.add_item(items[1],height=heights[1],expand=True)
                    
#
# Dialogs
#

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[0]

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 

#
# Windows
#

class WpfMenuBar():
    def __init__(self):
        self.ctrl = self.menubar = Menu()
        self.ctrl.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch
        self.ctrl.VerticalAlignment = System.Windows.VerticalAlignment.Top
    def add_menu(self,name,parent=None):
        self.menu = MenuItem()
        self.menu.Header = name; 
        if not parent: parent = self.menubar
        parent.Items.Add(self.menu)
        return self.menu
    def add_item(self,name,handler=None,icon=None,iconfile=None,tooltip=None,parent=None):
        item = MenuItem()
        if name: item.Header = name; 
        if handler: item.Click += handler
        if icon: image = Image(); image.Source = icon; item.Icon = image
        if iconfile: image = Image(); image.Source = self.get_imagefile(iconfile); item.Icon = image
        if tooltip: tip = ToolTip(); tip.Content = tooltip; item.ToolTip = tip
        if not parent: parent = self.menu
        parent.Items.Add(item)
        return item
    def add_separater(self,parent=None):
        self.menu.Items.Add(Separator())    
    '''    
    def parse_menu(self,name,menu_table): #name,handler,icon,tooltip or name,submenu,icon
        menu = MenuItem()
        menu.Header = name
        for m in menu_table:
            if m[0] is None or m[0] == '' or m[0] == '-':
                menu.Items.Add(Separator())
                continue
            if m[1] == None: continue # Disabled
            if type(m[1]) == list:
                menu.Items.Add(self.parse_menu(m[0],m[1]))
            else:
                item = MenuItem()
                item.Header = m[0]
                if len(m) > 1 and m[1] is not None: item.Click += m[1]
                if len(m) > 2 and m[2] is not None: item.Icon = m[2]
                if len(m) > 3 and m[3] is not None: pass
                menu.Items.Add(item)     
        return menu
    def add_ezmenu(self,menu_table):
        for m in menu_table:
            self.menubar.Items.Add(self.parse_menu(m[0],m[1])) 
    '''
    def add_ezmenuitem(self,menubar,menuitem):
        def find_menuitem(menu,name):
            if name == '-':
                menu.Items.Add(Separator())
            else:
                for item in menu.Items:
                    if type(item) == MenuItem and item.Header == name:
                        return item
                item = MenuItem()
                item.Header = name
                menu.Items.Add(item)
                return item
        menu = menubar
        for i in range(len(menuitem)):
            if menu is not None:
                if type(menuitem[i]) == str:
                    menu = find_menuitem(menu,menuitem[i])
                elif callable(menuitem[i]):
                    menu.Click += menuitem[i]
                else: 
                    menu.Icon = menuitem[i]
    def add_ezmenubar(self,menu_table):
        for m in menu_table:
            self.add_ezmenuitem(self.menubar,m)                    
    def get_imagefile(self,filename):
        return BitmapImage(System.Uri(filename,System.UriKind.Relative))

class WpfStatusBar():
    def __init__(self):
        self.ctrl = StatusBar()
        self.ctrl.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
        self.ctrl.VerticalAlignment = System.Windows.VerticalAlignment.Bottom;        
    def add_item(self,ctrl):
        item = StatusBarItem()
        item.Content = ctrl.ctrl  
        self.ctrl.Items.Add(item)
    def add_separater(self,parent=None):
        self.ctrl.Items.Add(Separator())  
    def add_ezstatus(self,status_table):
        for v in status_table:
            self.add_item( v )   
    def add_label(self,text):
        label = Label()
        label.Content = text
        self.add_item( label )    
    def add_button(self,text,handler=None):
        button = Button()
        button.Content = text
        if handler: button.Click += handler
        self.add_item( button.ctrl )    

class WpfToolBar():
    def __init__(self):
        self.ctrl = ToolBarTray()
        self.add_toolbar()
    def add_toolbar(self,parent=None):
        self.toolbar = ToolBar()
        self.toolbar.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
        self.toolbar.VerticalAlignment = System.Windows.VerticalAlignment.Bottom;
        if not parent: parent = self.ctrl
        parent.AddChild(self.toolbar)
    def add_item(self,ctrl,handler=None,icon=None,tooltip=None,parent=None):
        if handler: ctrl.Click += handler
        if icon: ctrl.Icon = icon
        if tooltip: tip = ToolTip(); tip.Content = tooltip; ctrl.ToolTip = tip
        if not parent: parent = self.toolbar
        parent.Items.Add(ctrl)
    def add_separater(self,parent=None):
        if not parent: parent = self.toolbar
        parent.Items.Add(Separator())
    def add_button(self,text=None,handler=None,icon=None,):
        button = WpfButton(text,handler,icon)
        self.toolbar.Items.Add(button.ctrl)        
    def add_eztool(self,tool_table):
        for v in tool_table:
            if v[0] is None or v[0] == '' or v[0] == '-':
                self.add_separater()
            else:
                icon = v[2] if len(v) > 2 and v[2] is not None else None
                self.add_button( v[0], v[1], icon )        
    def get_image(self,filename):
        return BitmapImage(System.Uri(filename,System.UriKind.Relative))

class Win(Window):
    def __init__(self,title=None,width=None,height=None):
        global top_wnd 
        top_wnd = self
        self.Closing += self.on_close
        if title: self.Title = title
        if width: self.Width = width
        if height:self.Height= height
        self.vbox = WpfVBox()
        self.Content = self.vbox.ctrl
        self.menubar = None
        self.toolbar = None
        self.statusbar = None
        self.content = None
    def set_title(self,title):  self.Title = title
    def set_icon(self,image): self.Icon = image
    def set_iconfile(self,imagefile): self.Icon = self.get_imagefile(imagefile)
    def set_width(self,width): self.Width = width
    def set_height(self,height): self.Height = height
    def set_size(self,width,height): self.Width = width; self.Height = height
    def add_statusbar(self,status): self.statusbar = status
    def set_ezmenubar(self,layout):
        self.menubar = WpfMenuBar()
        self.menubar.add_ezmenu(layout)
    def add_ezmenubar(self,layout):
        self.menubar = WpfMenuBar()
        self.menubar.add_ezmenubar(layout)
    def set_eztoolbar(self,layout):
        self.toolbar = WpfToolBar()
        self.toolbar.add_eztool(layout)
    def set_ezstatusbar(self,layout):
        self.statusbar = WpfStatusBar()
        self.statusbar.add_ezstatus(layout)
    def set_ezcontent(self,v):
        vbox = WpfVBox()
        for h in v:
            height = h[1] if len(h) > 1 else 0
            hbox = WpfHBox()
            for ctrl in h[0]:
                width = ctrl[1] if len(ctrl) > 1 else 0
                if height > 0: ctrl[0].set_height(height)
                if width > 0: ctrl[0].set_width(width)
                hbox.add_item( ctrl[0], expand=True if width == 0 else False )
            vbox.add_item( hbox, expand=True if height == 0 else False )
        self.content = vbox
    def run(self): 
        if self.menubar: self.vbox.add_item(self.menubar,expand=False)    
        if self.toolbar: self.vbox.add_item(self.toolbar,expand=False)    
        if self.content: self.vbox.add_item(self.content,expand=True)    
        if self.statusbar: self.vbox.add_item(self.statusbar,expand=False)    
        self.Show(); 
        Application().Run(self) 
    def close(self): self.Close()
    def on_close(self,sender,event):
        rv = MessageBox.Show("Do you want to close ?", "Warning", MessageBoxButton.YesNo )
        if rv == MessageBoxResult.Yes:
            event.Cancel = False
        else:
            event.Cancel = True
    def get_imagefile(self,filename): return wpf_icon.GetBitmapFrameFromFile(filename)
    def set_keydown(self,handler): self.KeyDown += handler

if __name__ == "__main__":
    import wpf_icon as ic

    def setMenuBar():
        app.add_ezmenubar(
             [[ 'File', 'Exit', on_exit, ic.GetExitImage() ],
              [ 'File', '-'],
              [ 'File', 'About', on_about ], 
              [ 'Help', 'About', on_about ]]        
        )

    def setToolBar():
        app.set_eztoolbar( 
            [[ 'Exit', on_exit, ic.GetExitImage(16) ],
             [  None, None ],
             [ 'About', on_about ]]
        )
  
    def setStatusBar():
        global progress
        global label1
        progress= WpfProgress(20,100)
        label1  = WpfLabel(text="Ready", width=100)
        button1 = WpfButton(text="Run", handler = on_run, width=48)
        button2 = WpfButton(text="Image", handler = on_image, width=48)
        button3 = WpfButton(image=ic.GetExitImage(16), handler = lambda s,e: app.Close(), width=32)
        app.set_ezstatusbar( [ progress, label1, button1, button2, button3 ] )

    def setContent():
        global table_view, image2
        listbox  = WpfList(("apple","grape","pear","melon"),handler=on_combo)
        combobox = WpfCombo(("apple","grape"),handler=on_combo)
        checkbox = WpfCheck("Click",handler=on_check)
        textbox  = WpfEdit(multiline=False)
        button   = WpfButton(image=ic.GetExitImage(),handler=on_exit)
                
        stc = WpfEdit()
        web = WpfWeb()
        split = WpfHSplit()
        split.add_items((stc,web))
        
        table_view = WpfTable(handler=on_table)
        table_view.add_columns(["One","Two"])
        table_view.add_items(("1111111111","222222222"))
        table_view.add_items(("33","44"))

        image2 = WpfImage(imagefile='D:/Lenna.png')
        tab = WpfTab()
        tab.add_item("List",table_view)
        tab.add_item("Edit/Web",split)    
        tab.add_item("Image",WpfImage(imagefile='D:/Lenna.png',stretch='none'))    
        tab.add_item("Image2",image2)    
        
        h1 = [[ listbox, -1 ],
              [ combobox, -1 ],
              [ checkbox, -1 ],
              [ textbox, 0 ],
              [ button, 48 ]]
        h2 = [[ tab, 0 ]]       
        #app.set_ezcontent( [[ h1, 48 ], 
        #                    [ h2, 0 ]] 
        #                 )     
        app.set_ezcontent( [[ h2, 0 ]] 
                         ) 
    def on_close(sender,event):
        rv = WpfYesNoDialog("Do you want to close ?", "Warning" )
        if rv == System.Windows.Forms.DialogResult.Yes: 
            event.Cancel = False
        else: event.Cancel = True
    def on_exit(sender,event):
        app.Close()
    def on_about(sender,event):
        WpfAlertDialog("About Winform.py", "Information" )
    def on_combo(sender,event):
        print(sender.SelectedItem)
    def on_check(sender,event):
        print(sender.IsChecked)
    def on_table(sender,event):
        items = table_view.get_selected_items()
        for i in items: print(i)
    def on_run(sender,event):
        StartTask(th_handler)
    def on_image(sender,event):
        import zip
        z = zip.PyUnZip("D:/image.zip")
        image2.set_image(GetImageSource(bytes(z.read(z.list()[1])).ToByteArray())) 
        #image2.set_imagefile("D:/a.png")
    def update_status(i):
        progress.set_value(i)
        label1.set_value(i)
    def th_handler():
        for i in range(100):
            RunLater(progress.ctrl, lambda : update_status(i))   
            Delay(100)     

    app = Win("Window Demo",320,240)
    app.set_icon(wpf_icon.GetExitImageSource())
    #app.set_icon(icon.GetBitmapFrameFromFile("exit.png"))
    
    setMenuBar()
    #setToolBar()
    setContent()
    setStatusBar()

    app.run()

댓글 없음:

댓글 쓰기