Changeset 103 for trunk

Show
Ignore:
Timestamp:
09/27/08 03:49:56 (4 years ago)
Author:
lgs
Message:

First version that actually draws charts

Location:
trunk/chavier
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • trunk/chavier/app.py

    r101 r103  
     1import cairo 
     2 
    13from pycha.chart import DEFAULT_OPTIONS 
     4from pycha.bar import VerticalBarChart 
    25 
    36from chavier.gui import GUI 
     
    1316        return DEFAULT_OPTIONS 
    1417 
     18    def get_chart(self, datasets, options, width, height): 
     19        surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) 
     20        chart = VerticalBarChart(surface, DEFAULT_OPTIONS) 
     21        chart.addDataset(datasets) 
     22        chart.render() 
     23        return surface 
     24 
    1525if __name__ == '__main__': 
    1626    app = App() 
  • trunk/chavier/gui.py

    r101 r103  
    66    def __init__(self, app): 
    77        self.app = app 
     8 
     9        self.surface = None 
    810 
    911        self.main_window = gtk.Window(gtk.WINDOW_TOPLEVEL) 
     
    3537        block1 = self._create_sidebar_block(u'Data sets', 
    3638                                            self._datasets_notebook_creator) 
    37         hbuttons = self._create_datasets_buttons() 
    38         block1.pack_start(hbuttons, False, False) 
    39         hbuttons.show() 
     39        self._create_dataset("Dataset 1") 
     40        block1.set_size_request(-1, 200) 
    4041 
    4142        vpaned.add1(block1) 
     
    4748        block2.show() 
    4849 
    49         drawing_area = gtk.DrawingArea() 
    50         hpaned.add2(drawing_area) 
    51         drawing_area.show() 
     50        self.drawing_area = gtk.DrawingArea() 
     51        self.drawing_area.connect('expose_event', 
     52                                  self.drawing_area_expose_event) 
     53        self.drawing_area.connect('size_allocate', 
     54                                  self.drawing_area_size_allocate_event) 
     55        hpaned.add2(self.drawing_area) 
     56        self.drawing_area.show() 
    5257 
    5358        self.main_window.show() 
     
    6166        action_group.add_actions([ 
    6267                ('file', None, '_File', None, 'File', None), 
    63                 ('quit', gtk.STOCK_QUIT, '_Quit', None, 'Quit the program', 
     68                ('quit', gtk.STOCK_QUIT, None, None, 'Quit the program', 
    6469                 self.quit), 
     70 
     71                ('edit', None, '_Edit', None, 'Edit', None), 
     72                ('add_dataset', gtk.STOCK_ADD, '_Add dataset', 
     73                 '<ctrl><alt>plus', 'Add another dataset', self.add_dataset), 
     74                ('remove_dataset', gtk.STOCK_REMOVE, '_Remove dataset', 
     75                 '<ctrl><alt>minus', 'Remove the current dataset', 
     76                 self.remove_dataset), 
     77                ('edit_dataset', gtk.STOCK_EDIT, '_Edit dataset name', 
     78                 '<ctrl><alt>e', 'Edit the name of the current dataset', 
     79                 self.edit_dataset), 
     80                ('add_point', gtk.STOCK_ADD, 'Add _point', '<ctrl>plus', 
     81                 'Add another point to the current dataset', self.add_point), 
     82                ('remove_point', gtk.STOCK_REMOVE, 'Remove p_oint', 
     83                 '<ctrl>minus', 
     84                 'Remove the current point of the current dataset', 
     85                 self.remove_point), 
     86                ('edit_point', gtk.STOCK_EDIT, 'Edit po_int', '<ctrl>e', 
     87                 'Edit the current point of the current dataset', 
     88                 self.edit_point), 
     89 
    6590                ('view', None, '_View', None, 'View', None), 
    66                 ('refresh', gtk.STOCK_REFRESH, '_Refresh', None, 'Update the chart', 
    67                  self.refresh), 
     91                ('refresh', gtk.STOCK_REFRESH, None, '<ctrl>r', 
     92                 'Update the chart', self.refresh), 
    6893                ]) 
    6994        uimanager.insert_action_group(action_group, -1) 
     
    7398    <menu action="file"> 
    7499      <menuitem action="quit"/> 
     100    </menu> 
     101    <menu action="edit"> 
     102      <menuitem action="add_dataset"/> 
     103      <menuitem action="remove_dataset"/> 
     104      <menuitem action="edit_dataset"/> 
     105      <separator /> 
     106      <menuitem action="add_point"/> 
     107      <menuitem action="remove_point"/> 
     108      <menuitem action="edit_point"/> 
    75109    </menu> 
    76110    <menu action="view"> 
     
    79113  </menubar> 
    80114  <toolbar name="ToolBar"> 
     115    <toolitem action="quit"/> 
     116    <separator /> 
     117    <toolitem action="add_dataset"/> 
     118    <toolitem action="remove_dataset"/> 
     119    <separator /> 
     120    <toolitem action="add_point"/> 
     121    <toolitem action="remove_point"/> 
     122    <separator /> 
    81123    <toolitem action="refresh"/> 
    82124  </toolbar> 
     
    110152        return self.datasets_notebook 
    111153 
    112     def _create_datasets_buttons(self): 
    113         hbuttons = gtk.HButtonBox() 
    114         hbuttons.set_layout(gtk.BUTTONBOX_END) 
    115  
    116         add_button = gtk.Button(stock=gtk.STOCK_ADD) 
    117         add_button.connect('clicked', self.add_dataset) 
    118         hbuttons.pack_start(add_button, False, False) 
    119         add_button.show() 
    120  
    121         remove_button = gtk.Button(stock=gtk.STOCK_REMOVE) 
    122         hbuttons.pack_start(remove_button, False, False) 
    123         remove_button.show() 
    124         remove_button.set_sensitive(False) 
    125  
    126         return hbuttons 
    127  
    128154    def _dataset_treeview_creator(self): 
    129155        store = gtk.ListStore(float, float) 
     
    176202                self.options_store.append(parent_node, (name, value)) 
    177203 
     204    def _get_current_dataset_tab(self): 
     205        current_tab = self.datasets_notebook.get_current_page() 
     206        if current_tab != -1: 
     207            return self.datasets_notebook.get_nth_page(current_tab) 
     208 
     209    def _create_dataset(self, name): 
     210        scrolled_window = self._dataset_treeview_creator() 
     211        scrolled_window.show() 
     212        label = gtk.Label(name) 
     213        self.datasets_notebook.append_page(scrolled_window, label) 
     214 
     215    def _get_datasets(self): 
     216        datasets = [] 
     217        n_pages = self.datasets_notebook.get_n_pages() 
     218        for i in range(n_pages): 
     219            tab = self.datasets_notebook.get_nth_page(i) 
     220            label = self.datasets_notebook.get_tab_label(tab) 
     221            name = label.get_label() 
     222            treeview = tab.get_children()[0] 
     223            model = treeview.get_model() 
     224            points = [(x, y) for x, y in model] 
     225            datasets.append((name, points)) 
     226        return datasets 
     227 
    178228    def run(self): 
    179229        gtk.main() 
     
    185235        gtk.main_quit() 
    186236 
     237    def drawing_area_expose_event(self, widget, event, data=None): 
     238        if self.surface is None: 
     239            return 
     240 
     241        cr = widget.window.cairo_create() 
     242        cr.rectangle(event.area.x, event.area.y, 
     243                     event.area.width, event.area.height) 
     244        cr.clip() 
     245        cr.set_source_surface(self.surface, 0, 0) 
     246        cr.paint() 
     247 
     248    def drawing_area_size_allocate_event(self, widget, event, data=None): 
     249        if self.surface is not None: 
     250            self.refresh() 
     251 
    187252    def quit(self, action): 
    188253        self.main_window.destroy() 
    189254 
    190     def add_dataset(self, button, data=None): 
     255    def add_dataset(self, action): 
    191256        n_pages = self.datasets_notebook.get_n_pages() 
    192257        suggested_name = u'Dataset %d' % (n_pages + 1) 
     
    195260        if response == gtk.RESPONSE_ACCEPT: 
    196261            name = dialog.get_name() 
    197             scrolled_window = self._dataset_treeview_creator() 
    198             scrolled_window.show() 
    199             label = gtk.Label(name) 
    200             self.datasets_notebook.append_page(scrolled_window, label) 
     262            self._create_dataset(name) 
    201263        dialog.destroy() 
    202264 
    203     def refresh(self, action): 
    204         pass 
     265    def remove_dataset(self, action): 
     266        current_tab = self.datasets_notebook.get_current_page() 
     267        assert current_tab != -1 
     268 
     269        self.datasets_notebook.remove_page(current_tab) 
     270 
     271    def edit_dataset(self, action): 
     272        tab = self._get_current_dataset_tab() 
     273        assert tab is not None 
     274 
     275        label = self.datasets_notebook.get_tab_label(tab) 
     276        name = label.get_label() 
     277        dialog = TextInputDialog(self.main_window, name) 
     278        response = dialog.run() 
     279        if response == gtk.RESPONSE_ACCEPT: 
     280            name = dialog.get_name() 
     281            label.set_label(name) 
     282        dialog.destroy() 
     283 
     284    def add_point(self, action): 
     285        tab = self._get_current_dataset_tab() 
     286        assert tab is not None 
     287 
     288        treeview = tab.get_children()[0] 
     289        model = treeview.get_model() 
     290 
     291        dialog = PointDialog(self.main_window, len(model) * 1.0, 0.0) 
     292        response = dialog.run() 
     293        if response == gtk.RESPONSE_ACCEPT: 
     294            x, y = dialog.get_point() 
     295            model.append((x, y)) 
     296            self.refresh() 
     297        dialog.destroy() 
     298 
     299    def remove_point(self, action): 
     300        tab = self._get_current_dataset_tab() 
     301        assert tab is not None 
     302 
     303        treeview = tab.get_children()[0] 
     304        selection = treeview.get_selection() 
     305        model, selected = selection.get_selected() 
     306        if selected is None: 
     307            warning(self.main_window, "You must select the point to remove") 
     308            return 
     309 
     310        model.remove(selected) 
     311        self.refresh() 
     312 
     313    def edit_point(self, action): 
     314        tab = self._get_current_dataset_tab() 
     315        assert tab is not None 
     316 
     317        treeview = tab.get_children()[0] 
     318        selection = treeview.get_selection() 
     319        model, selected = selection.get_selected() 
     320        if selected is None: 
     321            warning(self.main_window, "You must select the point to edit") 
     322            return 
     323 
     324        x, y = model.get(selected, 0, 1) 
     325 
     326        dialog = PointDialog(self.main_window, x, y) 
     327        response = dialog.run() 
     328        if response == gtk.RESPONSE_ACCEPT: 
     329            x, y = dialog.get_point() 
     330            model.set(selected, 0, x, 1, y) 
     331            self.refresh() 
     332        dialog.destroy() 
     333 
     334    def refresh(self, action=None): 
     335        datasets = self._get_datasets() 
     336#        options = self._get_options() 
     337 
     338        alloc = self.drawing_area.get_allocation() 
     339        self.surface = self.app.get_chart(datasets, None, 
     340                                          alloc.width, alloc.height) 
     341        self.drawing_area.queue_draw() 
     342 
     343 
    205344 
    206345class TextInputDialog(gtk.Dialog): 
     
    233372    def get_name(self): 
    234373        return self.entry.get_text() 
     374 
     375 
     376class PointDialog(gtk.Dialog): 
     377    def __init__(self, toplevel_window, initial_x, initial_y): 
     378        flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT 
     379        buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, 
     380                   gtk.STOCK_OK, gtk.RESPONSE_ACCEPT) 
     381        super(PointDialog, self).__init__(u'Enter a name for the dataset', 
     382                                          toplevel_window, flags, buttons) 
     383 
     384        initials = {u'x': str(initial_x), u'y': str(initial_y)} 
     385        self.entries = {} 
     386        for coordinate in (u'x', u'y'): 
     387            hbox = gtk.HBox(spacing=6) 
     388            hbox.set_border_width(12) 
     389 
     390            label = gtk.Label(coordinate) 
     391            hbox.pack_start(label, False, False) 
     392 
     393            entry = gtk.Entry() 
     394            entry.set_activates_default(True) 
     395            entry.set_text(initials[coordinate]) 
     396            hbox.pack_start(entry, True, True) 
     397 
     398            self.entries[coordinate] = entry 
     399 
     400            self.vbox.pack_start(hbox, False, False) 
     401 
     402        self.vbox.show_all() 
     403 
     404        self.set_default_response(gtk.RESPONSE_ACCEPT) 
     405 
     406    def get_point(self): 
     407        return (float(self.entries[u'x'].get_text()), 
     408                float(self.entries[u'y'].get_text())) 
     409 
     410 
     411def warning(window, msg): 
     412    dialog = gtk.MessageDialog(window, 
     413                               gtk.DIALOG_MODAL|gtk.DIALOG_DESTROY_WITH_PARENT, 
     414                               gtk.MESSAGE_WARNING, gtk.BUTTONS_OK, msg) 
     415    dialog.run() 
     416    dialog.destroy()