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

Add stack widget #124

Draft
wants to merge 19 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
Binary file added docs/assets/examples/stack.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,10 @@ The `widgets` directory contains examples for how to use different widgets.
<td><a href="https://github.com/can-lehmann/owlkettle/blob/main/examples/widgets/search_entry.nim">Search Entry</a></td>
<td><img alt="Search Entry Widget" src="../docs/assets/examples/search_entry.png" width="688px"></td>
</tr>
<tr>
<td><a href="https://github.com/can-lehmann/owlkettle/blob/main/examples/widgets/stack.nim">Stack</a></td>
<td><img alt="Stack" src="../docs/assets/examples/stack.png" width="922px"></td>
</tr>
<tr>
<td><a href="https://github.com/can-lehmann/owlkettle/blob/main/examples/widgets/text_view.nim">Text View</a></td>
<td><img alt="Text View" src="../docs/assets/examples/text_view.png" width="757px"></td>
Expand Down
110 changes: 110 additions & 0 deletions examples/widgets/stack.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# MIT License
#
# Copyright (c) 2022 Can Joshua Lehmann
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

import std/[sequtils]
import owlkettle, owlkettle/[dataentries, playground, adw]

type DummyPage = tuple[
name: string,
title: string,
text: string,
visible: bool,
useUnderline: bool,
needsAttention: bool,
iconName: string
]

let stackPages: seq[DummyPage] = (1..2).mapIt((
"Widget " & $it,
"Title _" & $it,
"I am stack page " & $it,
true,
true,
false,
""
))

viewable App:
hhomogenous: bool = true
interpolateSize: bool = true
transitionDuration: uint = 500
transitionType: StackTransitionType = StackTransitionSlideUp
vhomogenous: bool = true
visibleChildName: string = "Widget 1"
pages: seq[DummyPage] = stackPages
sensitive: bool = true
tooltip: string = ""
sizeRequest: tuple[x, y: int] = (-1, -1)

var counter = 0
method view(app: AppState): Widget =
echo "View run #", counter
counter.inc
let stack = gui:
Stack():
hhomogenous = app.hhomogenous
interpolateSize = app.interpolateSize
transitionDuration = app.transitionDuration
transitionType = app.transitionType
vhomogenous = app.vhomogenous
visibleChildName = app.visibleChildName
sensitive = app.sensitive
tooltip = app.tooltip
sizeRequest = app.sizeRequest

for page in app.pages:
StackPage():
name = page.name
title = page.title
iconName = page.iconName
visible = page.visible
useUnderline = page.useUnderline
needsAttention = page.needsAttention

Box():
Label(text = page.text)

result = gui:
Window():
title = "Stack Example"
defaultSize = (800, 400)
HeaderBar() {.addTitlebar.}:
insert(app.toAutoFormMenu(sizeRequest = (700, 600))) {.addRight.}

for page in app.pages:
Button(text = page.name) {.addRight.}:
style = [ButtonFlat]
proc clicked() =
app.visibleChildName = page.name

Box(orient = OrientY):
Label(text = app.pages[0].repr) {.expand: false.}
Label(text = app.pages[1].repr) {.expand: false.}

StackSidebar():
insert(stack)

insert(stack)



adw.brew(gui(App()))
56 changes: 55 additions & 1 deletion owlkettle/bindings/gtk.nim
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,31 @@ type
GTK_LEVEL_BAR_MODE_CONTINUOUS
GTK_LEVEL_BAR_MODE_DISCRETE

GtkStackTransitionType* = enum
GTK_STACK_TRANSITION_TYPE_NONE
GTK_STACK_TRANSITION_TYPE_CROSSFADE
GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT
GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT
GTK_STACK_TRANSITION_TYPE_SLIDE_UP
GTK_STACK_TRANSITION_TYPE_SLIDE_DOWN
GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT
GTK_STACK_TRANSITION_TYPE_SLIDE_UP_DOWN
GTK_STACK_TRANSITION_TYPE_OVER_UP
GTK_STACK_TRANSITION_TYPE_OVER_DOWN
GTK_STACK_TRANSITION_TYPE_OVER_LEFT
GTK_STACK_TRANSITION_TYPE_OVER_RIGHT
GTK_STACK_TRANSITION_TYPE_UNDER_UP
GTK_STACK_TRANSITION_TYPE_UNDER_DOWN
GTK_STACK_TRANSITION_TYPE_UNDER_LEFT
GTK_STACK_TRANSITION_TYPE_UNDER_RIGHT
GTK_STACK_TRANSITION_TYPE_OVER_UP_DOWN
GTK_STACK_TRANSITION_TYPE_OVER_DOWN_UP
GTK_STACK_TRANSITION_TYPE_OVER_LEFT_RIGHT
GTK_STACK_TRANSITION_TYPE_OVER_RIGHT_LEFT
GTK_STACK_TRANSITION_TYPE_ROTATE_LEFT
GTK_STACK_TRANSITION_TYPE_ROTATE_RIGHT
GTK_STACK_TRANSITION_TYPE_ROTATE_LEFT_RIGHT

GtkTextIter* = object
a, b: pointer
c, d, e, f, g, h: cint
Expand Down Expand Up @@ -158,6 +183,7 @@ type
GtkMediaStream* = distinct pointer
GtkListItemFactory* = distinct pointer
GtkSelectionModel* = distinct pointer
GtkStackPage* = distinct pointer

proc isNil*(obj: GtkTextBuffer): bool {.borrow.}
proc isNil*(obj: GtkTextTag): bool {.borrow.}
Expand All @@ -177,6 +203,9 @@ proc isNil*(obj: GtkParamSpec): bool {.borrow.}
proc isNil*(obj: GtkMediaStream): bool {.borrow.}
proc isNil*(obj: GtkListItemFactory): bool {.borrow.}
proc isNil*(obj: GtkSelectionModel): bool {.borrow.}
proc isNil*(obj: GtkStackPage): bool {.borrow.}

proc `==`*(x, y: GtkStackPage): bool {.borrow.}

template defineBitSet(typ) =
proc `==`*(a, b: typ): bool {.borrow.}
Expand Down Expand Up @@ -928,8 +957,33 @@ when GtkMinor >= 10:
proc gtk_search_entry_set_placeholder_text*(widget: GtkWidget, text: cstring)

# Gtk.Stack
proc gtk_stack_add_named*(stack, child: GtkWidget, name: cstring)
proc gtk_stack_new*(): GtkWidget
proc gtk_stack_add_named*(stack, child: GtkWidget, name: cstring): GtkStackPage
proc gtk_stack_remove*(stack, child: GtkWidget)
proc gtk_stack_add_titled*(stack, child: GtkWidget, name: cstring, title: cstring): GtkStackPage
proc gtk_stack_set_hhomogeneous*(stack: GtkWidget, hhomogeneous: cbool)
proc gtk_stack_set_interpolate_size*(stack: GtkWidget, interpolate_size: cbool)
proc gtk_stack_set_transition_duration*(stack: GtkWidget, duration: cuint)
proc gtk_stack_set_transition_type*(stack: GtkWidget, transition: GtkStackTransitionType)
proc gtk_stack_set_vhomogeneous*(stack: GtkWidget, vhomogeneous: cbool)
proc gtk_stack_set_visible_child*(stack, child: GtkWidget)
proc gtk_stack_set_visible_child_name*(stack: GtkWidget, name: cstring)

# Gtk.StackPage
proc gtk_stack_page_set_icon_name*(self: GtkStackPage, setting: cstring)
proc gtk_stack_page_set_name*(self: GtkStackPage, setting: cstring)
proc gtk_stack_page_set_needs_attention*(self: GtkStackPage, setting: cbool)
proc gtk_stack_page_set_title*(self: GtkStackPage, setting: cstring)
proc gtk_stack_page_set_use_underline*(self: GtkStackPage, setting: cbool)
proc gtk_stack_page_set_visible*(self: GtkStackPage, visible: cbool)

# Gtk.StackSwitcher
proc gtk_stack_switcher_new*(): GtkWidget
proc gtk_stack_switcher_set_stack*(switcher, stack: GtkWidget)

# Gtk.StackSidebar
proc gtk_stack_sidebar_new*(): GtkWidget
proc gtk_stack_sidebar_set_stack*(sidebar, stack: GtkWidget)

# Gtk.MenuButton
proc gtk_menu_button_new*(): GtkWidget
Expand Down
29 changes: 29 additions & 0 deletions owlkettle/playground.nim
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,35 @@ proc toFormField(state: Viewable, field: ptr ScaleMark, fieldName: string): Widg
proc select(enumIndex: int) =
field[].position = enumIndex.ScalePosition

proc toFormField(state: auto, fieldName: static string, index: int, typ: typedesc[tuple[name: string, title: string, text: string]]): Widget =
## Provides a form to display a single entry of type `tuple[name: string, title: string, text: string]` in a list of entries.
let tup = state.getField(fieldName)[index]
return gui:
ActionRow:
title = "(Name, Title, Text)"
Entry() {.addSuffix.}:
text = state.getField(fieldName)[index].name
proc changed(text: string) =
state.getField(fieldName)[index].name = text

Entry() {.addSuffix.}:
text = state.getField(fieldName)[index].title
proc changed(text: string) =
state.getField(fieldName)[index].title = text

Entry() {.addSuffix.}:
text = state.getField(fieldName)[index].text
proc changed(text: string) =
state.getField(fieldName)[index].text = text

Button {.addSuffix.}:
icon = "user-trash-symbolic"
proc clicked() =
state.getField(fieldName).delete(index)

proc toFormField[T](state: auto, fieldName: static string, typ: typedesc[seq[T]]): Widget =
## Provides a form field for any field on `state` with a seq type.
## Displays a dummy widget if there is no `toListFormField` implementation for type T.
proc addDeleteButton(formField: Widget, value: ptr seq[auto], index: int) =
let button = gui:
Button():
Expand Down
Loading