Changeset 3268

Show
Ignore:
Timestamp:
07/31/08 15:40:50 (5 years ago)
Author:
nopper
Message:

New expander implementation (pure python)

Location:
branch/PacketManipulator/widgets
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • branch/PacketManipulator/widgets/Expander.py

    r3261 r3268  
    1919# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 
    2020 
     21 
    2122import gtk 
    2223import gobject 
    2324 
     25from gtk import gdk 
    2426from higwidgets.higbuttons import HIGArrowButton 
     27 
     28# 
     29# Reimplementation of gtk.Layout in python 
     30# Example on how to implement a scrollable container in python 
     31# 
     32# Johan Dahlin <johan@gnome.org>, 2006 
     33# 
     34# Readaption for implementing show/hide animation and only one child by 
     35# Francesco Piccinno <stack.box@gmail.com>, 2008 
     36# 
     37# Requires PyGTK 2.8.0 or later 
     38 
     39class Child: 
     40    widget = None 
     41    x = 0 
     42    y = 0 
     43 
     44def set_adjustment_upper(adj, upper, always_emit): 
     45    changed = False 
     46    value_changed = False 
     47 
     48    min = max(0.0, upper - adj.page_size) 
     49 
     50    if upper != adj.upper: 
     51        adj.upper = upper 
     52        changed = True 
     53 
     54    if adj.value > min: 
     55        adj.value = min 
     56        value_changed = True 
     57 
     58    if changed or always_emit: 
     59        adj.changed() 
     60    if value_changed: 
     61        adj.value_changed() 
     62 
     63def new_adj(): 
     64    return gtk.Adjustment(0.0, 0.0, 0.0, 
     65                          0.0, 0.0, 0.0) 
     66 
     67class Layout(gtk.Container): 
     68    __gsignals__ = { 
     69        'animation-end' : (gobject.SIGNAL_RUN_LAST, None, (gobject.TYPE_BOOLEAN, )), 
     70        'set_scroll_adjustments' : (gobject.SIGNAL_RUN_LAST, None, 
     71                                   (gtk.Adjustment, gtk.Adjustment)) 
     72    } 
     73 
     74    def __init__(self): 
     75        self._child = None 
     76        self._width = 100 
     77        self._height = 100 
     78        self._hadj = None 
     79        self._vadj = None 
     80        self._bin_window = None 
     81        self._hadj_changed_id = -1 
     82        self._vadj_changed_id = -1 
     83 
     84        self._animating = False 
     85        self._to_show = True 
     86 
     87        self._current = 0 
     88        self._dest = 0 
     89        self._speed = 5 
     90 
     91        self._time_int = 10 
     92        self._time_tot = 300 
     93 
     94        gtk.Container.__init__(self) 
     95 
     96        if not self._hadj or not self._vadj: 
     97            self._set_adjustments(self._vadj or new_adj(), 
     98                                  self._hadj or new_adj()) 
     99 
     100    def _move(self, x=0, y=0): 
     101        if not self._child: 
     102            return 
     103 
     104        if x != self._child.x or \ 
     105           y != self._child.y: 
     106 
     107            self._child.x = x 
     108            self._child.y = y 
     109 
     110            self.queue_resize() 
     111 
     112    def set_size(self, width, height): 
     113        if self._width != width: 
     114            self._width = width 
     115        if self._height != height: 
     116            self._height = height 
     117        if self._hadj: 
     118            set_adjustment_upper(self._hadj, self._width, False) 
     119        if self._vadj: 
     120            set_adjustment_upper(self._vadj, self._height, False) 
     121 
     122        if self.flags() & gtk.REALIZED: 
     123            self._bin_window.resize(max(width, self.allocation.width), 
     124                                    max(height, self.allocation.height)) 
     125 
     126    def do_realize(self): 
     127        self.set_flags(self.flags() | gtk.REALIZED) 
     128 
     129        self.window = gdk.Window( 
     130            self.get_parent_window(), 
     131            window_type=gdk.WINDOW_CHILD, 
     132            x=self.allocation.x, 
     133            y=self.allocation.y, 
     134            width=self.allocation.width, 
     135            height=self.allocation.height, 
     136            wclass=gdk.INPUT_OUTPUT, 
     137            colormap=self.get_colormap(), 
     138            event_mask=gdk.VISIBILITY_NOTIFY_MASK) 
     139        self.window.set_user_data(self) 
     140 
     141        self._bin_window = gdk.Window( 
     142            self.window, 
     143            window_type=gdk.WINDOW_CHILD, 
     144            x=int(-self._hadj.value), 
     145            y=int(-self._vadj.value), 
     146            width=max(self._width, self.allocation.width), 
     147            height=max(self._height, self.allocation.height), 
     148            colormap=self.get_colormap(), 
     149            wclass=gdk.INPUT_OUTPUT, 
     150            event_mask=(self.get_events() | gdk.EXPOSURE_MASK | 
     151                        gdk.SCROLL_MASK)) 
     152        self._bin_window.set_user_data(self) 
     153 
     154        self.set_style(self.style.attach(self.window)) 
     155        self.style.set_background(self.window, gtk.STATE_NORMAL) 
     156        self.style.set_background(self._bin_window, gtk.STATE_NORMAL) 
     157 
     158        if self._child: 
     159            self._child.widget.set_parent_window(self._bin_window) 
     160 
     161        self.queue_resize() 
     162 
     163    def do_unrealize(self): 
     164        self._bin_window.set_user_data(None) 
     165        self._bin_window.destroy() 
     166        self._bin_window = None 
     167        gtk.Container.do_unrealize(self) 
     168 
     169    def _do_style_set(self, style): 
     170        gtk.Widget.do_style_set(self, style) 
     171 
     172        if self.flags() & gtk.REALIZED: 
     173            self.style.set_background(self._bin_window, gtk.STATE_NORMAL) 
     174 
     175    def do_expose_event(self, event): 
     176        if event.window != self._bin_window: 
     177            return False 
     178 
     179        gtk.Container.do_expose_event(self, event) 
     180 
     181        return False 
     182 
     183    def do_map(self): 
     184        self.set_flags(self.flags() | gtk.MAPPED) 
     185 
     186        if self._child: 
     187            flags = self._child.widget.flags() 
     188 
     189            if flags & gtk.VISIBLE and not (flags & gtk.MAPPED): 
     190                self._child.widget.map() 
     191 
     192        self._bin_window.show() 
     193        self.window.show() 
     194 
     195    def do_size_request(self, req): 
     196        req.width = 0 
     197        req.height = 0 
     198 
     199        if self._child and (self._animating or self._to_show): 
     200        #if self._child: 
     201            req.width, req.height = self._child.widget.size_request() 
     202 
     203    def do_size_allocate(self, allocation): 
     204        self.allocation = allocation 
     205 
     206        if self._child: 
     207            rect = gdk.Rectangle(self._child.x, self._child.y, 
     208                                 allocation.width, allocation.height) 
     209            self._child.widget.size_allocate(rect) 
     210 
     211        if self.flags() & gtk.REALIZED: 
     212            self.window.move_resize(*allocation) 
     213            self._bin_window.resize(max(self._width, allocation.width), 
     214                                    max(self._height, allocation.height)) 
     215 
     216        self._hadj.page_size = allocation.width 
     217        self._hadj.page_increment = allocation.width * 0.9 
     218        self._hadj.lower = 0 
     219        set_adjustment_upper(self._hadj, 
     220                             max(allocation.width, self._width), True) 
     221 
     222        self._vadj.page_size = allocation.height 
     223        self._vadj.page_increment = allocation.height * 0.9 
     224        self._vadj.lower = 0 
     225        self._vadj.upper = max(allocation.height, self._height) 
     226        set_adjustment_upper(self._vadj, 
     227                             max(allocation.height, self._height), True) 
     228 
     229    def do_set_scroll_adjustments(self, hadj, vadj): 
     230        self._set_adjustments(hadj, vadj) 
     231 
     232    def do_forall(self, include_internals, callback, data): 
     233        if self._child: 
     234            callback(self._child.widget, data) 
     235 
     236    def do_add(self, widget): 
     237        if self._child: 
     238            raise AttributeError 
     239 
     240        child = Child() 
     241        child.widget = widget 
     242        child.x, child.y = 0, 0 
     243 
     244        self._child = child 
     245 
     246        if self.flags() & gtk.REALIZED: 
     247            widget.set_parent_window(self._bin_window) 
     248 
     249        widget.set_parent(self) 
     250 
     251    def do_remove(self, widget): 
     252        if self._animating: 
     253            raise Exception("Try later please :)") 
     254 
     255        if self._child and self._child.widget == widget: 
     256            self._child = None 
     257            widget.unparent() 
     258        else: 
     259            raise AttributeError 
     260 
     261    # Private 
     262 
     263    def _set_adjustments(self, hadj, vadj): 
     264        if not hadj and self._hadj: 
     265            hadj = new_adj() 
     266 
     267        if not vadj and self._vadj: 
     268            vadj = new_adj() 
     269 
     270        if self._hadj and self._hadj != hadj: 
     271            self._hadj.disconnect(self._hadj_changed_id) 
     272 
     273        if self._vadj and self._vadj != vadj: 
     274            self._vadj.disconnect(self._vadj_changed_id) 
     275 
     276        need_adjust = False 
     277 
     278        if self._hadj != hadj: 
     279            self._hadj = hadj 
     280            set_adjustment_upper(hadj, self._width, False) 
     281            self._hadj_changed_id = hadj.connect( 
     282                "value-changed", 
     283                self._adjustment_changed) 
     284            need_adjust = True 
     285 
     286        if self._vadj != vadj: 
     287            self._vadj = vadj 
     288            set_adjustment_upper(vadj, self._height, False) 
     289            self._vadj_changed_id = vadj.connect( 
     290                "value-changed", 
     291                self._adjustment_changed) 
     292            need_adjust = True 
     293 
     294        if need_adjust and vadj and hadj: 
     295            self._adjustment_changed() 
     296 
     297    def _adjustment_changed(self, adj=None): 
     298        if self.flags() & gtk.REALIZED: 
     299            self._bin_window.move(int(-self._hadj.value), 
     300                                  int(-self._vadj.value)) 
     301            self._bin_window.process_updates(True) 
     302 
     303    def _do_animation(self): 
     304        if not self._child: 
     305            return False 
     306 
     307        if not self._child.widget.flags() & gtk.VISIBLE: 
     308            self._child.widget.show() 
     309 
     310        if self._to_show: 
     311            if self._current < 0: 
     312                self._current += self._speed 
     313                self._move(0, self._current) 
     314 
     315                return True 
     316 
     317            self._current = 0 
     318            self._move(0, self._current) 
     319        else: 
     320            if self._current > self._dest: 
     321                self._current -= self._speed 
     322                self._move(0, self._current) 
     323 
     324                return True 
     325 
     326            self._current = -self.allocation.height 
     327            self._move(0, self._current) 
     328 
     329            self.hide() 
     330 
     331        self.emit('animation-end', self._to_show) 
     332        self._child.widget.set_sensitive(True) 
     333        return False 
     334 
     335    def toggle_animation(self): 
     336        if self._animating or not self._child: 
     337            return False 
     338 
     339        self._to_show = not self._to_show 
     340        self._speed = max(self.allocation.height / (self._time_tot / self._time_int), 1) 
     341        self._child.widget.set_sensitive(False) 
     342 
     343        if self._to_show: 
     344            self.show() 
     345            self.set_size_request(-1, -1) 
     346            self._dest = 0 
     347        else: 
     348            self.set_size_request(0, 0) 
     349            self._dest = -self.allocation.height 
     350 
     351        gobject.timeout_add(self._time_int, self._do_animation) 
     352 
     353        return True 
     354 
     355Layout.set_set_scroll_adjustments_signal('set-scroll-adjustments') 
    25356 
    26357class AnimatedExpander(gtk.VBox): 
     
    33364        # optionally a close button :) 
    34365         
    35         self.arrow = HIGArrowButton(gtk.ORIENTATION_VERTICAL) 
    36         self.arrow.set_relief(gtk.RELIEF_NONE) 
    37         self.arrow.connect('clicked', self.__on_toggle) 
     366        self._arrow = HIGArrowButton(gtk.ORIENTATION_VERTICAL) 
     367        self._arrow.set_relief(gtk.RELIEF_NONE) 
     368        self._arrow.connect('clicked', self.__on_toggle) 
    38369         
    39370        self._label = gtk.Label() 
     
    45376         
    46377        # The layout part 
    47         self.layout = gtk.Layout() 
    48         self.child = None 
    49          
    50         self.animating = False 
    51         self.to_show = False 
    52          
    53         self.speed = 10 
    54         self.current = 0 
    55         self.dest = 0 
    56  
    57         self.tot_time = 100 
    58         self.int_time = 5 
     378        self._layout = Layout() 
    59379         
    60380        # Pack all 
    61381        hbox = gtk.HBox(False, 2) 
    62         hbox.pack_start(self.arrow, False, False) 
     382        hbox.pack_start(self._arrow, False, False) 
    63383        hbox.pack_start(self._image, False, False) 
    64384        hbox.pack_start(self._label) 
     
    67387        frame.add(hbox) 
    68388         
    69         self.happy_box = gtk.EventBox() 
    70         self.happy_box.add(frame) 
    71          
    72         self.pack_start(self.happy_box, False, False) 
    73         self.pack_end(self.layout) 
     389        self._happy_box = gtk.EventBox() 
     390        self._happy_box.add(frame) 
     391         
     392        self.pack_start(self._happy_box, False, False) 
     393        self.pack_start(self._layout) 
    74394         
    75395        self.show_all() 
     
    81401        gtk.gdk.colormap_get_system().alloc_color(bg_color) 
    82402 
    83         self.happy_box.modify_bg(gtk.STATE_NORMAL, bg_color) 
    84  
    85     def do_size_allocate(self, allocation): 
    86         ret = gtk.VBox.do_size_allocate(self, allocation) 
    87  
    88         if self.animating: 
    89             self.layout.show() 
    90         elif self.child and not self.animating: 
    91             alloc = self.layout.get_allocation() 
    92             w, h = alloc.width, alloc.height 
    93              
    94             alloc = self.child.get_allocation() 
    95  
    96             #if w > alloc.width: 
    97             if w >= self.child.size_request()[0]: 
    98                 alloc.width = w 
    99             else: 
    100                 alloc.width = self.child.size_request()[0] 
    101  
    102             #if h > alloc.height: 
    103             if h >= self.child.size_request()[1]: 
    104                 alloc.height = h 
    105             else: 
    106                 alloc.height = self.child.size_request()[1] 
    107  
    108             self.child.size_allocate(alloc) 
    109              
    110             if self.to_show: 
    111                 self.layout.show() 
    112             else: 
    113                 self.layout.hide() 
    114          
    115         return ret 
     403        self._happy_box.modify_bg(gtk.STATE_NORMAL, bg_color) 
    116404 
    117405    def add_widget(self, widget, show=False): 
    118406        """ 
    119407        Add a widget to the expander. 
    120          
     408 
    121409        @param widget the widget to add 
    122410        @param show if the widget should be showed 
    123411        """ 
    124          
    125         if self.child: 
    126             raise Exception("Could not add another widget as child.") 
    127          
    128         self.child = widget 
    129          
    130         self.layout.put(self.child, 0, 0) 
    131         self.do_size_allocate(self.get_allocation()) 
    132         self.set_expanded(show) 
     412 
     413        #FIXME: this 
     414        self._layout.add(widget) 
    133415 
    134416    def add(self, widget): 
    135417        self.add_widget(widget, True) 
    136  
    137     def set_expanded(self, val): 
    138         """ 
    139         Show or hide the child widget without animation 
    140         """ 
    141          
    142         if not self.child: 
    143             return 
    144          
    145         self.arrow.set_active(val) 
    146         self.to_show = val 
    147  
    148         if val: 
    149             self.current = 0 
    150             self.layout.move(self.child, 0, self.current) 
    151             self.layout.show() 
    152         else: 
    153             self.layout.hide() 
    154             self.current = self.__get_child_height() 
    155             self.layout.move(self.child, 0, self.current) 
    156          
    157         if not self.animating: 
    158             self.__set_animating(False) 
    159418 
    160419    def get_label(self): 
     
    168427        self._label.set_use_markup(True) 
    169428 
    170     def __animate_hide(self): 
    171         if self.current > self.dest: 
    172             self.current -= self.speed 
    173             self.layout.move(self.child, 0, self.current) 
    174  
    175             return True 
    176  
    177         if self.dest < 0: 
    178             self.layout.hide() 
    179          
    180         self.current = self.__get_child_height() 
    181         self.__set_animating(False) 
    182         self.arrow.set_sensitive(True) 
    183          
    184         return False 
    185  
    186     def __animate_show(self): 
    187         if self.current < 0: 
    188             self.current += self.speed 
    189             self.layout.move(self.child, 0, self.current) 
    190  
    191             return True 
    192          
    193         self.current = 0 
    194         self.layout.move(self.child, 0, 0) 
    195         self.__set_animating(False) 
    196         self.arrow.set_sensitive(True) 
    197          
    198         return False 
    199      
    200  
    201429    def __on_toggle(self, btn): 
    202         if not self.child: 
    203             return 
    204          
    205         self.arrow.set_active(not self.arrow.get_active()) 
    206         self.to_show = self.arrow.get_active() 
    207         self.__set_animating(True) 
    208          
    209         self.arrow.set_sensitive(False) 
    210  
    211         # We need to calculate the speed offset to complete 
    212         # the scrolling in self.tot_time 
    213  
    214         self.speed = self.__get_child_height() / (self.tot_time / self.int_time) 
    215  
    216         # Avoid null scrolling 
    217         if self.speed < 5: 
    218             self.speed = 5 
    219  
    220         if self.to_show: 
    221             self.dest = 0 
    222             self.current = -self.__get_child_height() 
    223              
    224             gobject.timeout_add(self.int_time, self.__animate_show) 
    225         else: 
    226             self.dest = -self.__get_child_height() 
    227             self.current = 0 
    228              
    229             gobject.timeout_add(self.int_time, self.__animate_hide) 
    230      
    231     def __get_child_height(self): 
    232         if self.child.flags() & gtk.REALIZED: 
    233             return self.child.get_allocation().height 
    234         else: 
    235             return self.child.size_request()[1] 
    236  
    237     def __set_animating(self, val): 
    238         self.animating = val 
    239  
    240         if not self.child: 
    241             return 
    242  
    243         self.child.set_sensitive(not self.animating) 
    244  
    245         alloc = self.layout.get_allocation() 
    246  
    247         if self.to_show: 
    248             alloc.height = self.__get_child_height() 
    249             self.layout.set_size_request(-1, alloc.height + 2) 
    250         else: 
    251             alloc.height = 0 
    252             self.layout.set_size_request(-1, -1) 
    253          
    254         self.layout.size_allocate(alloc) 
    255         self.size_allocate(self.get_allocation()) 
     430        if self._layout.toggle_animation(): 
     431            self._arrow.set_active(not self._arrow.get_active()) 
    256432     
    257433    def get_image(self): 
     
    266442gobject.type_register(AnimatedExpander) 
    267443 
     444class ToolPage(AnimatedExpander): 
     445    def __init__(self, parent, label=None, image=gtk.STOCK_PROPERTIES): 
     446        super(ToolPage, self).__init__(label, image) 
     447 
     448        self._parent = parent 
     449        self._active = False 
     450 
     451        self._layout.connect('animation-end', lambda w, v: self.set_active(v)) 
     452 
     453    def get_active(self): 
     454        return self._active 
     455 
     456    def set_active(self, val): 
     457        self._active = val 
     458        self._parent.realloc(self) 
     459 
     460class ToolBox(gtk.VBox): 
     461    def __init__(self): 
     462        super(ToolBox, self).__init__(False, 2) 
     463        self.set_border_width(4) 
     464 
     465        self._active_page = None 
     466        self._pages = [] 
     467 
     468    def append_page(self, child, txt): 
     469        page = ToolPage(self, txt) 
     470        page.add(child) 
     471 
     472        self._pages.append(page) 
     473 
     474 
     475        self._active_page = page 
     476        self.pack_start(page, True, True) 
     477 
     478    def realloc(self, page): 
     479        if page.get_active(): 
     480            self.set_child_packing(page, True, True, 0, gtk.PACK_START) 
     481 
     482            if self._active_page: 
     483                self._active_page.set_active(False) 
     484                self._active_page = page 
     485        else: 
     486            self.set_child_packing(page, False, False, 0, gtk.PACK_START) 
     487 
     488def main(klass): 
     489    w = gtk.Window() 
     490    vbox = gtk.VBox() 
     491 
     492    sw = gtk.ScrolledWindow() 
     493    sw.add(gtk.TextView()) 
     494    sw.set_size_request(400, 400) 
     495     
     496    exp = klass("miao") 
     497    exp.add(sw) 
     498 
     499    vbox.pack_start(exp, False, False) 
     500 
     501    sw = gtk.ScrolledWindow() 
     502    sw.add(gtk.TextView()) 
     503     
     504    exp = klass("miao") 
     505    exp.add(sw) 
     506    vbox.pack_start(exp) 
     507 
     508    vbox.pack_start(gtk.Label("mias"), False, False) 
     509    w.add(vbox) 
     510    w.show_all() 
     511 
     512def toolbox(): 
     513    w = gtk.Window() 
     514    box = ToolBox() 
     515    box.append_page(gtk.Label("Testing"), "miao") 
     516    box.append_page(gtk.Label("Testing"), "miao") 
     517    w.add(box) 
     518    w.show_all() 
     519 
    268520if __name__ == "__main__": 
    269     w = gtk.Window() 
    270     exp = AnimatedExpander("<b>Testinggggg</b>") 
    271     sw = gtk.ScrolledWindow() 
    272     exp.add_widget(gtk.Label("Miao")) 
    273     w.add(exp) 
    274     w.show_all() 
     521    #main(AnimatedExpander) 
     522    #main(gtk.Expander) 
     523    toolbox() 
    275524    gtk.main() 
  • branch/PacketManipulator/widgets/PropertyGrid.py

    r3249 r3268  
    3636# Higwidgets 
    3737from higwidgets.hignetwidgets import HIGIpEntry 
     38from widgets.Expander import AnimatedExpander 
    3839 
    3940class Editor(gtk.HBox): 
     
    595596class PropertyGrid(gtk.VBox): 
    596597    def __init__(self): 
    597         gtk.VBox.__init__(self) 
     598        gtk.VBox.__init__(self, False, 2) 
     599 
     600        self.set_border_width(2) 
    598601 
    599602        self.__create_toolbar() 
     
    605608        self.tree = PropertyGridTree() 
    606609 
    607         self.expander = gtk.Expander("Description") 
    608  
    609610        self.desc_text = gtk.TextView() 
    610611        self.desc_text.set_wrap_mode(gtk.WRAP_WORD) 
    611         self.desc_text.set_size_request(1, 70) 
     612        #self.desc_text.set_size_request(1, 70) 
    612613        self.desc_text.set_editable(False) 
    613614        self.desc_text.set_left_margin(5) 
     
    619620        sw.add(self.desc_text) 
    620621 
    621         self.expander.add(sw) 
    622          
    623         self.pack_start(self.tree) 
    624         self.pack_start(self.expander, False, False) 
     622        expander = AnimatedExpander('Protocol') 
     623        expander.add(self.tree) 
     624 
     625        self.pack_start(expander) 
     626 
     627        expander = AnimatedExpander('Description') 
     628        expander.add(sw) 
     629 
     630        self.pack_start(expander, False, False) 
    625631 
    626632        self.clear = self.tree.clear