Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

View pivot table #56

Merged
merged 38 commits into from
May 28, 2024
Merged
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
32cd129
add .idea to ignore file
Apr 8, 2024
2b14d8c
add card controller
Apr 8, 2024
f74c796
view add
Apr 8, 2024
99b82dc
add get_all() method to repo
Apr 8, 2024
30c983e
init sored object realization done
Apr 8, 2024
277eedd
add get_all method to mock repo
Apr 8, 2024
162e9be
apply new object id
SardorSharipov Apr 20, 2024
7ea5dfb
add text object
Apr 30, 2024
d32d2aa
view by state machine
Apr 30, 2024
ea71f33
update controller and repo
Apr 30, 2024
67800b7
update required libs
Apr 30, 2024
c5d6eae
exclude view from test
Apr 30, 2024
7f5ab88
add font to class
May 1, 2024
17b6086
add tests to object with font
May 1, 2024
41950d6
card view
May 1, 2024
77ca6f4
update tests and methods
May 1, 2024
7ec577d
linter check
May 1, 2024
a9a98c4
add pen object
May 4, 2024
c887d9c
update test
May 4, 2024
2cce4e8
update pen tests
May 4, 2024
2116b84
added attributes
Aplsn May 8, 2024
0b32390
added pivot table
Aplsn May 10, 2024
8e466d4
fixed bugs
Aplsn May 10, 2024
80cb93b
merged main
May 26, 2024
f87a57b
add table to view
May 26, 2024
f81b6b4
update controller
May 26, 2024
a1671ef
add init file
May 26, 2024
14e6782
fixed events
Aplsn May 26, 2024
05a59cd
fixed submenu
Aplsn May 26, 2024
1d3457e
fixed serializing
Aplsn May 26, 2024
6dad4d7
fixed bugs
Aplsn May 26, 2024
16f7733
Merge remote-tracking branch 'origin/view-pivot-table' into view-pivo…
Aplsn May 26, 2024
4b050c6
fixed bugs
Aplsn May 26, 2024
a00a55c
add git ignore
May 28, 2024
50ddea0
main merged
May 28, 2024
99c0d59
change attributed controller
May 28, 2024
5b71a49
add pivot table
May 28, 2024
dd3fea2
fixed bugs
Aplsn May 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
added pivot table
  • Loading branch information
Aplsn committed May 10, 2024
commit 0b323900cecf2161bb037686c698f13d21f0c204
8 changes: 4 additions & 4 deletions src/internal/controller/impl/controller.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import logging
import typing
from copy import deepcopy

import internal.models
import internal.objects
@@ -176,34 +175,35 @@ def add_attribute(
attr_name: str
# attr: internal.models.Attribute
):
print()
for obj in self._repo.get_all():
if not isinstance(obj, internal.objects.interfaces.IBoardObjectCard):
continue
print(obj.text)

card: internal.objects.interfaces.IBoardObjectCard = obj
card.attributes[attr_name] = None
logging.debug(
'adding new attribute with name=%s',
attr_name
)

def edit_attribute(
self,
obj_id: internal.objects.interfaces.ObjectId,
attr_name: str,
value: str
):
# print(attr_name)
obj: typing.Optional[
internal.objects.interfaces.IBoardObjectCard
] = self._repo.get(obj_id)
# print(obj.attributes)
if obj:
logging.debug(
'editing attribute of an object old value=%s with new value=%s',
obj.attributes[attr_name],
value
)
obj.attributes = value
obj.attributes[attr_name] = value
self._on_feature_finish()
return
logging.debug('no object id=%s found to edit with attribute=%s', obj_id, attr_name)
9 changes: 6 additions & 3 deletions src/internal/objects/impl/card.py
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@
_TEXT_FIELD = 'text'
_FONT_FIELD = 'font'
_COLOR_FIELD = 'color'
_ATTRIBUTES_FIELD = 'attributes'
_ATTRIBUTES_FIELD = 'attributes_dict'

class BoardObjectCard(interfaces.IBoardObjectCard, BoardObjectWithFont):
def __init__(
@@ -49,14 +49,17 @@ def attributes(self, attributes: dict) -> None:
def serialize(self) -> dict:
serialized = super().serialize()
serialized[_COLOR_FIELD] = self.color
serialized[_ATTRIBUTES_FIELD] = self.attributes
serialized[_ATTRIBUTES_FIELD] = list(map(lambda x: [x[0], x[1]], self.attributes.items()))
return serialized

@staticmethod
def from_serialized(
data: dict,
pub_sub_broker: internal.pub_sub.interfaces.IPubSubBroker,
) -> BoardObjectCard:
temp = dict()
for key, value in data[_ATTRIBUTES_FIELD]:
temp[key] = value

# TODO: child class should not know how to build parent from serialized data
return BoardObjectCard(
@@ -66,5 +69,5 @@ def from_serialized(
data[_TEXT_FIELD],
internal.models.Font.from_serialized(data[_FONT_FIELD]),
data[_COLOR_FIELD],
data[_ATTRIBUTES_FIELD]
temp
)
3 changes: 2 additions & 1 deletion src/internal/view/modules/card/property_bar.py
Original file line number Diff line number Diff line change
@@ -136,7 +136,7 @@ def _attribute_widget(
getter: Callable,
setter: Callable
) -> List[ttk.Widget]:
string_var = tkinter.StringVar()
string_var = tkinter.StringVar(value=getter(dependencies, obj_id, description))
label = ttk.Label(
dependencies.property_bar,
text=description,
@@ -279,6 +279,7 @@ def _get_attribute(
attr_name: str
):
card: internal.objects.interfaces.IBoardObjectCard = dependencies.repo.get(obj_id)
print(card.attributes[attr_name])
return card.attributes[attr_name]
# return dependencies.canvas.itemcget(CARD_NOTE_PREFIX + obj_id, 'fill')

4 changes: 3 additions & 1 deletion src/internal/view/modules/table_view/__init__.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
from __future__ import annotations

import internal.view.dependencies
from .states import add_attribute
from .states import add_attribute, show_axis
from .view import open_window as open_window


def create_states(dependencies: internal.view.dependencies):
dependencies.state_machine.add_state(add_attribute.create_state(dependencies.state_machine))
dependencies.state_machine.add_state(show_axis.create_state(dependencies.state_machine))


def register_module_menu(dependencies: internal.view.dependencies):
dependencies.menu.add_command_to_menu(add_attribute.ADD_ATTR_MENU_ENTRY_NAME)
dependencies.menu.add_command_to_menu(show_axis.SHOW_TABLE_MENU_ENTRY_NAME)


@internal.view.modules.modules.register_module('table_view')
44 changes: 21 additions & 23 deletions src/internal/view/modules/table_view/states/add_attribute.py
Original file line number Diff line number Diff line change
@@ -7,17 +7,16 @@
from internal.view.state_machine.impl import State
import internal.view.state_machine.interfaces
import internal.view.dependencies
from ..view import open_window, get_values
from ..toplevel import Window
from ..view import open_window, NAME
ADD_ATTR_MENU_ENTRY_NAME = 'add attribute'
ADD_ATTRIBUTE_STATE_NAME = 'ADD_ATTRIBUTE'
_WINDOW = 'window_add'
_ENTRY = 'entry'
_NAME = 'name'
_WINDOW = 'toplevel_window'


def _predicate_from_root_to_add_attribute(
global_dependencies: internal.view.dependencies.Dependencies,
event: tkinter.Event
_: tkinter.Event
) -> bool:
if global_dependencies.menu.current_state != ADD_ATTR_MENU_ENTRY_NAME:
return False
@@ -29,38 +28,37 @@ def _on_enter(
state_ctx: Dict,
_: tkinter.Event
):
state_ctx[_WINDOW], state_ctx[_ENTRY] = open_window(global_dependencies)
# name = get_values(state_ctx[_WINDOW], state_ctx[_ENTRY])
# print(name)
# if name:
# global_dependencies.controller.add_attribute(name)
state_ctx[_WINDOW] = open_window(global_dependencies)


def _on_leave(
global_dependencies: internal.view.dependencies.Dependencies,
state_ctx: Dict,
_: tkinter.Event
):
name: Window = state_ctx[_WINDOW]
if name.saved:
global_dependencies.controller.add_attribute(name.get_vals()[NAME])
global_dependencies.menu.set_selected_state()


# def _handle_event(
# global_dependencies: internal.view.dependencies.Dependencies,
# state_ctx: Dict,
# event: tkinter.Event
# ):
# name = get_values(state_ctx[_WINDOW], state_ctx[_ENTRY])
# print(name)
# if name:
# global_dependencies.controller.add_attribute(name)

def _predicate_from_add_attribute_to_root(
global_dependencies: internal.view.dependencies.Dependencies,
event: tkinter.Event
) -> bool:
# ВОТ ТУТ должен быть ивент выхода из конкретного окна, иначе все ломается
if event.type != tkinter.EventType.Destroy:
if event.type != tkinter.EventType.Deactivate:
return False
return global_dependencies.menu.current_state == ADD_ATTRIBUTE_STATE_NAME

return True


def create_state(
state_machine: internal.view.state_machine.interfaces.IStateMachine
) -> State:
state = State(ADD_ATTRIBUTE_STATE_NAME)
state.set_on_enter(_on_enter)
# state.set_event_handler(_handle_event)
state.set_on_leave(_on_leave)
state_machine.add_transition(
internal.view.state_machine.interfaces.ROOT_STATE_NAME,
ADD_ATTRIBUTE_STATE_NAME,
157 changes: 157 additions & 0 deletions src/internal/view/modules/table_view/states/show_axis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
from __future__ import annotations
from typing import Dict
import tkinter

import internal.objects
import internal.models.position
from internal.view.state_machine.impl import State
import internal.view.state_machine.interfaces
import internal.view.dependencies
from internal.models import Position
from ..toplevel import Window
from ..view import show_axis, draw_table, get_attr_from_position

SHOW_TABLE_MENU_ENTRY_NAME = 'pivot table'
CHOSE_AXIS_STATE_NAME = 'SHOW_TABLE'
_WINDOW = 'window_add'
_TABLE = 'table_window'
_NAME = 'name'
_INITIAL_POSITION = 'obj_position'
_LAST_DRAG_EVENT_X = 'last_drag_event_x'
_LAST_DRAG_EVENT_Y = 'last_drag_event_y'
_FIRST_DRAG_EVENT_X = 'first_drag_event_x'
_FIRST_DRAG_EVENT_Y = 'first_drag_event_y'
_OBJ_ID = 'obj_id'
_MOVE_STARTED = 'moving'
_X_LIST = 'x_list'
_Y_LIST = 'y_list'
_X_OPTIONS = 'x_options'
_Y_OPTIONS = 'y_options'
_WIDTH = 'width'
_HEIGHT = 'height'


def _predicate_from_root_to_add_attribute(
global_dependencies: internal.view.dependencies.Dependencies,
event: tkinter.Event
) -> bool:
if global_dependencies.menu.current_state != SHOW_TABLE_MENU_ENTRY_NAME:
return False
return True


def _on_enter(
global_dependencies: internal.view.dependencies.Dependencies,
state_ctx: Dict,
_: tkinter.Event
):
state_ctx[_WINDOW] = show_axis(global_dependencies)
state_ctx[_MOVE_STARTED] = False
global_dependencies.menu.set_selected_state()

def _handle_event(
global_dependencies: internal.view.dependencies.Dependencies,
state_ctx: Dict,
event: tkinter.Event
):
window: Window = state_ctx[_WINDOW]
if event.type == tkinter.EventType.Deactivate and window and window.saved:
table, x_list, x_options, y_list, y_options, width, height = draw_table(global_dependencies, window.get_vals())
table.canvas.bind('<B1-Motion>', lambda event: move_obj_start(state_ctx, event, state_ctx[_TABLE]))
table.canvas.bind('<ButtonRelease-1>', lambda event: moving_stop(global_dependencies, state_ctx, event, state_ctx[_TABLE]))
state_ctx[_TABLE] = table
state_ctx[_X_LIST] = x_list
state_ctx[_Y_LIST] = y_list
state_ctx[_X_OPTIONS] = x_options
state_ctx[_Y_OPTIONS] = y_options
state_ctx[_WIDTH] = width
state_ctx[_HEIGHT] = height

return


def move_obj_start(
state_ctx: Dict,
event: tkinter.Event,
window: Window
):
if state_ctx[_MOVE_STARTED]:
x = int(window.canvas.canvasx(event.x))
y = int(window.canvas.canvasy(event.y))
window.canvas.move(
state_ctx[_OBJ_ID],
x - state_ctx[_LAST_DRAG_EVENT_X],
y - state_ctx[_LAST_DRAG_EVENT_Y]
)
state_ctx[_LAST_DRAG_EVENT_X] = x
state_ctx[_LAST_DRAG_EVENT_Y] = y
return

tags = window.canvas.gettags('current')
if not tags:
return
state_ctx[_MOVE_STARTED] = True
window.canvas.scan_mark(event.x, event.y)

x = int(window.canvas.canvasx(event.x))
y = int(window.canvas.canvasy(event.y))

state_ctx[_LAST_DRAG_EVENT_X] = x
state_ctx[_LAST_DRAG_EVENT_Y] = y

state_ctx[_FIRST_DRAG_EVENT_X] = x
state_ctx[_FIRST_DRAG_EVENT_Y] = y
state_ctx[_INITIAL_POSITION] = Position(x, y, 1)
state_ctx[_OBJ_ID] = tags[0]


def moving_stop(
global_dependencies: internal.view.dependencies.Dependencies,
state_ctx: Dict,
_: tkinter.Event,
window: Window
):
if not state_ctx[_MOVE_STARTED]:
return
state_ctx[_MOVE_STARTED] = False
diff: Position = Position(
state_ctx[_LAST_DRAG_EVENT_X] - state_ctx[_FIRST_DRAG_EVENT_X],
state_ctx[_LAST_DRAG_EVENT_Y] - state_ctx[_FIRST_DRAG_EVENT_Y],
0
)
position = state_ctx[_INITIAL_POSITION] + diff

attributes = get_attr_from_position(position, state_ctx[_X_LIST], state_ctx[_X_OPTIONS], state_ctx[_Y_LIST],
state_ctx[_Y_OPTIONS], state_ctx[_WIDTH], state_ctx[_HEIGHT])
for name, value in attributes.items():
global_dependencies.controller.edit_attribute(state_ctx[_OBJ_ID], name, value)
window.canvas.configure(background='white')


def _predicate_from_add_attribute_to_root(
global_dependencies: internal.view.dependencies.Dependencies,
event: tkinter.Event
) -> bool:
if event.type != tkinter.EventType.Property:
return False
return True


def create_state(
state_machine: internal.view.state_machine.interfaces.IStateMachine
) -> State:
state = State(CHOSE_AXIS_STATE_NAME)
state.set_on_enter(_on_enter)
state.set_event_handler(_handle_event)
state_machine.add_transition(
internal.view.state_machine.interfaces.ROOT_STATE_NAME,
CHOSE_AXIS_STATE_NAME,
_predicate_from_root_to_add_attribute
)
state_machine.add_transition(
CHOSE_AXIS_STATE_NAME,
internal.view.state_machine.interfaces.ROOT_STATE_NAME,
_predicate_from_add_attribute_to_root
)

return state
37 changes: 37 additions & 0 deletions src/internal/view/modules/table_view/toplevel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import tkinter
from tkinter import ttk

import internal.objects.interfaces
import internal.view.dependencies


class Window(tkinter.Toplevel):
def __init__(self,
dependencies: internal.view.dependencies.Dependencies,
canvas: bool = False
):
super(Window, self).__init__(dependencies.canvas)
self.dependencies = dependencies
# self.window = dependencies.canvas
if canvas:
self.canvas = tkinter.Canvas(self, width=1200, height=600, bg='white')
self.canvas.pack(expand=False)

self.entries = dict()
self.saved = False

def add_entry(self, name):
self.entries[name] = ttk.Entry(self)
return self.entries[name]

def add_combobox(self, name, vals):
self.entries[name] = ttk.Combobox(self, values=vals, state='readonly')
return self.entries[name]

def get_vals(self):
if self.saved:
tmp = dict()
for name, entry in self.entries.items():
tmp[name] = entry.get()
return tmp
return None
Loading