UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2014 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <inttypes.h> 33 34 #include "tree.h" 35 36 #include "container.h" 37 #include "../common/object.h" 38 #include "../common/context.h" 39 #include <cx/utils.h> 40 #include <cx/compare.h> 41 #include <cx/printf.h> 42 43 UIWIDGET ui_table_var(UiObject *obj, UiVar *var, UiModel *model, UiListCallbacks cb) { 44 // TODO: check if modelinfo is complete 45 46 Arg args[32]; 47 int n = 0; 48 49 // create scrolled window 50 UiContainer *ct = uic_get_current_container(obj); 51 Widget parent = ct->prepare(ct, args, &n, TRUE); 52 53 XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); 54 n++; 55 XtSetArg(args[n], XmNshadowThickness, 0); 56 n++; 57 Widget scrollw = XmCreateScrolledWindow(parent, "scroll_win", args, n); 58 ct->add(ct, scrollw); 59 XtManageChild(scrollw); 60 61 // create table headers 62 XmStringTable header = (XmStringTable)XtMalloc( 63 model->columns * sizeof(XmString)); 64 for(int i=0;i<model->columns;i++) { 65 header[i] = XmStringCreateLocalized(model->titles[i]); 66 } 67 n = 0; 68 XtSetArg(args[n], XmNdetailColumnHeading, header); 69 n++; 70 XtSetArg(args[n], XmNdetailColumnHeadingCount, model->columns); 71 n++; 72 73 // set res 74 XtSetArg(args[n], XmNlayoutType, XmDETAIL); 75 n++; 76 XtSetArg(args[n], XmNentryViewType, XmSMALL_ICON); 77 n++; 78 XtSetArg(args[n], XmNselectionPolicy, XmSINGLE_SELECT); 79 n++; 80 XtSetArg(args[n], XmNwidth, 600); 81 n++; 82 83 // create widget 84 //UiContainer *ct = uic_get_current_container(obj); 85 //Widget parent = ct->add(ct, args, &n); 86 87 Widget container = XmCreateContainer(scrollw, "table", args, n); 88 XtManageChild(container); 89 90 // add callbacks 91 UiTreeEventData *event = ui_malloc(obj->ctx, sizeof(UiTreeEventData)); 92 event->obj = obj; 93 event->activate = cb.activate; 94 event->selection = cb.selection; 95 event->userdata = cb.userdata; 96 event->last_selection = NULL; 97 if(cb.selection) { 98 XtAddCallback( 99 container, 100 XmNselectionCallback, 101 (XtCallbackProc)ui_table_select_callback, 102 event); 103 } 104 if(cb.activate) { 105 XtAddCallback( 106 container, 107 XmNdefaultActionCallback, 108 (XtCallbackProc)ui_table_action_callback, 109 event); 110 } 111 112 // add initial data 113 UiList *list = var->value; 114 void *data = list->first(list); 115 int width = 0; 116 while(data) { 117 int w = ui_add_icon_gadget(container, model, data); 118 if(w > width) { 119 width = w; 120 } 121 data = list->next(list); 122 } 123 124 UiTableView *tableview = cxMalloc(obj->ctx->allocator, sizeof(UiTableView)); 125 tableview->widget = container; 126 tableview->var = var; 127 tableview->model = model; 128 129 // set new XmContainer width 130 XtVaSetValues(container, XmNwidth, width, NULL); 131 132 // cleanup 133 for(int i=0;i<model->columns;i++) { 134 XmStringFree(header[i]); 135 } 136 XtFree((char*)header); 137 138 return scrollw; 139 } 140 141 UIWIDGET ui_table(UiObject *obj, UiList *data, UiModel *model, UiListCallbacks cb) { 142 UiVar *var = malloc(sizeof(UiVar)); 143 var->value = data; 144 var->type = UI_VAR_SPECIAL; 145 return ui_table_var(obj, var, model, cb); 146 } 147 148 void ui_table_update(UiEvent *event, UiTableView *view) { 149 // clear container 150 Widget *children; 151 int nc; 152 153 XtVaGetValues( 154 view->widget, 155 XmNchildren, 156 &children, 157 XmNnumChildren, 158 &nc, 159 NULL); 160 161 for(int i=0;i<nc;i++) { 162 XtDestroyWidget(children[i]); 163 } 164 165 UiList *list = view->var->value; 166 167 void *data = list->first(list); 168 int width = 0; 169 while(data) { 170 int w = ui_add_icon_gadget(view->widget, view->model, data); 171 if(w > width) { 172 width = w; 173 } 174 data = list->next(list); 175 } 176 177 } 178 179 #define UI_COL_CHAR_WIDTH 12 180 181 int ui_add_icon_gadget(Widget container, UiModel *model, void *data) { 182 int width = 50; 183 184 if(model->columns == 0) { 185 return width; 186 } 187 188 XmString label = NULL; 189 Arg args[8]; 190 Boolean f; 191 // first column 192 if(model->types[0] != 12345678) { // TODO: icon/label type 193 char *str = ui_type_to_string( 194 model->types[0], 195 model->getvalue(data, 0), 196 &f); 197 198 // column width 199 width += strlen(str) * UI_COL_CHAR_WIDTH; 200 201 202 XmString label = XmStringCreateLocalized(str); 203 XtSetArg(args[0], XmNlabelString, label); 204 if(f) { 205 free(str); 206 } 207 } else { 208 // TODO 209 } 210 211 // remaining columns are the icon gadget details 212 XmStringTable details = (XmStringTable)XtMalloc( 213 (model->columns - 1) * sizeof(XmString)); 214 for(int i=1;i<model->columns;i++) { 215 char *str = ui_type_to_string( 216 model->types[i], 217 model->getvalue(data, i), 218 &f); 219 220 // column width 221 width += strlen(str) * UI_COL_CHAR_WIDTH; 222 223 details[i - 1] = XmStringCreateLocalized(str); 224 if(f) { 225 free(str); 226 } 227 } 228 XtSetArg(args[1], XmNdetail, details); 229 XtSetArg(args[2], XmNdetailCount, model->columns - 1); 230 XtSetArg(args[3], XmNshadowThickness, 0); 231 // create widget 232 Widget item = XmCreateIconGadget(container, "table_item", args, 4); 233 XtManageChild(item); 234 235 // cleanup 236 XmStringFree(label); 237 for(int i=0;i<model->columns-1;i++) { 238 XmStringFree(details[i]); 239 } 240 XtFree((char*)details); 241 242 return width; 243 } 244 245 char* ui_type_to_string(UiModelType type, void *data, Boolean *free) { 246 switch(type) { 247 case UI_STRING: *free = FALSE; return data; 248 case UI_INTEGER: { 249 *free = TRUE; 250 int *val = data; 251 cxmutstr str = cx_asprintf("%d", *val); 252 return str.ptr; 253 } 254 case UI_ICON: break; // TODO 255 case UI_ICON_TEXT: break; // TODO 256 } 257 *free = FALSE; 258 return NULL; 259 } 260 261 void ui_table_action_callback( 262 Widget widget, 263 UiTreeEventData *event, 264 XmContainerSelectCallbackStruct *sel) 265 { 266 UiListSelection *selection = ui_list_selection(sel); 267 268 UiEvent e; 269 e.obj = event->obj; 270 e.window = event->obj->window; 271 e.document = event->obj->ctx->document; 272 e.eventdata = selection; 273 e.intval = selection->count > 0 ? selection->rows[0] : -1; 274 event->activate(&e, event->userdata); 275 276 free(event->last_selection->rows); 277 free(event->last_selection); 278 event->last_selection = selection; 279 } 280 281 void ui_table_select_callback( 282 Widget widget, 283 UiTreeEventData *event, 284 XmContainerSelectCallbackStruct *sel) 285 { 286 UiListSelection *selection = ui_list_selection(sel); 287 if(!ui_compare_list_selection(selection, event->last_selection)) { 288 UiEvent e; 289 e.obj = event->obj; 290 e.window = event->obj->window; 291 e.document = event->obj->ctx->document; 292 e.eventdata = selection; 293 e.intval = selection->count > 0 ? selection->rows[0] : -1; 294 event->selection(&e, event->userdata); 295 } 296 if(event->last_selection) { 297 free(event->last_selection->rows); 298 free(event->last_selection); 299 } 300 event->last_selection = selection; 301 } 302 303 UiListSelection* ui_list_selection(XmContainerSelectCallbackStruct *xs) { 304 UiListSelection *selection = malloc(sizeof(UiListSelection)); 305 selection->count = xs->selected_item_count; 306 selection->rows = calloc(selection->count, sizeof(int)); 307 for(int i=0;i<selection->count;i++) { 308 int index; 309 XtVaGetValues(xs->selected_items[i], XmNpositionIndex, &index, NULL); 310 selection->rows[i] = index; 311 } 312 return selection; 313 } 314 315 Boolean ui_compare_list_selection(UiListSelection *s1, UiListSelection *s2) { 316 if(!s1 || !s2) { 317 return FALSE; 318 } 319 if(s1->count != s2->count) { 320 return FALSE; 321 } 322 for(int i=0;i<s1->count;i++) { 323 if(s1->rows[i] != s2->rows[i]) { 324 return FALSE; 325 } 326 } 327 return TRUE; 328 } 329